{"id":16318529,"url":"https://github.com/vic/blue","last_synced_at":"2025-10-25T06:11:01.822Z","repository":{"id":57480031,"uuid":"123326892","full_name":"vic/blue","owner":"vic","description":"Blue Velvet - Block Lisp Underneath Elixir.","archived":false,"fork":false,"pushed_at":"2018-11-25T00:12:16.000Z","size":19,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-31T10:04:15.407Z","etag":null,"topics":["elilxir","embedded-language","lisp","macros"],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vic.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-02-28T18:43:35.000Z","updated_at":"2020-06-29T21:28:15.000Z","dependencies_parsed_at":"2022-09-26T17:41:35.743Z","dependency_job_id":null,"html_url":"https://github.com/vic/blue","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vic%2Fblue","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vic%2Fblue/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vic%2Fblue/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vic%2Fblue/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vic","download_url":"https://codeload.github.com/vic/blue/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238191668,"owners_count":19431465,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["elilxir","embedded-language","lisp","macros"],"created_at":"2024-10-10T22:23:48.677Z","updated_at":"2025-10-25T06:10:56.781Z","avatar_url":"https://github.com/vic.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Blue Velvet LISP - Barely Lisp Under Elixir.\n\n\u003ca href=\"https://travis-ci.org/vic/blue\"\u003e\u003cimg src=\"https://travis-ci.org/vic/blue.svg\"\u003e\u003c/a\u003e\n[hexdocs](https://hexdocs.pm/blue).\n\n\nA minimalist LISP toy abusing Elixir own syntax.\n\nAs with any toy, dont take it to seriously, have fun with it,\nexperiment and learn.\n\nTake a look at the code, I tried to see how far I could\nget a nano lisp in elixir without any programming :P.\n\n[Official Soundtrack](https://www.youtube.com/watch?v=icfq_foa5Mo)\n\n## Elixir blocks\n\nIn Elixir you can create blocks by surrounding any number\nof expressions between parens and separating them by using\neither a new line or `;`.\n\n```elixir\n\n    # An inline block\n    iex\u003e {:__block__, _, items} = quote do: (1 ; 2 ; 3)\n    iex\u003e items\n    [1, 2, 3]\n\n\n    # Or by breaking lines\n    iex\u003e {:__block__, _, items} = quote do: (\n    ...\u003e    :one\n    ...\u003e    2 ; 3\n    ...\u003e    \"four\"\n    ...\u003e )\n    iex\u003e items\n    [:one, 2, 3, \"four\"]\n    \n```\n\n\n## The `Blue.blue/1` macro\n\nNow that we know how to create blocks, lets abuse them\nto evaluate lisp-like expressions.\n\nNotice that BLUE lisp works with Elixir AST directly\nand thus it has no reader. Instead, just create\nElixir blocks or lists and feed them to the `blue/1` macro.\n\nThe `blue/1` macro takes a single program and works by\ntransforming its list of items into valid Elixir AST\nfor function application.\n\n\n    \n```elixir\n\n    # Call blue with a program\n    iex\u003e import Blue\n    iex\u003e (blue 1) == (1) |\u003e blue\n    true\n\n    # Of course you can call any Elixir function\n    iex\u003e (blue (is_atom ; \"hello\"))\n    false\n\n    # Or call operators by breaking lines\n    # Remember all this is just valid Elixir syntax\n    iex\u003e (blue (+\n    ...\u003e    1\n    ...\u003e    2))\n    3\n\n    # Any atom can be used for calling operators or local functions\n    iex\u003e (blue (:*; 2; 3))\n    6\n\n    # Calling remote functions also works\n    iex\u003e (blue (Macro.camelize ; \"blue_velvet\"))\n    \"BlueVelvet\"\n\n\n    # But trying to apply to a non call fails.\n    # Remember this is just Elixir itself dressed as blue lisp.\n    iex\u003e (blue (1 ; 2))\n    ** (BadFunctionError) expected a function, got: 1\n    \n```\n\n\n## BLUE is also a Bracket LISP\n\nSometimes using BLUE's Bracket syntax can be useful,\nfor example when working with Keyword, or just if you\nprefer not to use Blocks everywhere.\n\n    \n```elixir\n\n    # A list syntax can also be given to blue\n    iex\u003e (blue [is_atom, :hello])\n    true\n\n    # And you can alternate between them as\n    # needed. To turn a list into a LISP program just\n    # remember to call `blue` with it.\n    iex\u003e (blue (to_string\n    ...\u003e   (blue [tuple_size, hello: :world])\n    ...\u003e ))\n    \"2\"\n    \n```\n\n\n\n## Everything happens at compile time\n\nAll the `blue/1` macro does is: given a list of items\nit expects the first to be a partial function application\nand merely appends the rest of items to it as arguments.\n\n    \n```elixir\n\n    # Keyword.get([hello: \"world], :hola, \"mundo\")\n    iex\u003e (blue (\n    ...\u003e   Keyword.get([hello: \"world\"])\n    ...\u003e   :hola\n    ...\u003e   \"mundo\"\n    ...\u003e ))\n    \"mundo\"\n\n\n    # Thats why the anon function wont be called here\n    iex\u003e (blue (fn -\u003e 9 end)) |\u003e is_function\n    true\n\n\n    # The following would produce a compilation error.\n    # Because `99` would be appended as just another\n    # argument to the `fn` form, at compile time.\n    iex\u003e Code.eval_string \"\n    ...\u003e   import Blue\n    ...\u003e   (blue ( fn x -\u003e x end ; 99 ))\n    ...\u003e \"\n    ** (FunctionClauseError) no function clause matching in anonymous fn/1 in :elixir_fn.expand/3\n\n\n    # To work around this, you can use `Kernel.apply/2`\n    iex\u003e (blue (apply ; fn x -\u003e x end ; [99] ))\n    99\n\n    # Same for function references\n    iex\u003e (blue (apply ; \u0026Macro.underscore/1 ; [Blue.Velvet] ))\n    \"blue/velvet\"\n    \n```\n\n\n## Special forms\n\n### `\u0026rest` arguments\n\nFunctions in Erlang/Elixir have fixed arity, that is, they cannot\ntake a variable number of arguments. To work around this, the convention\nis to make functions take a list as last argument.\n\n\nUsing `\u0026rest` captures the following items in a list as a single argument.\n\n    \n```elixir\n\n    # Use it on any function taking lists at last argument\n    iex\u003e (blue (Enum.max; \u0026rest; 4; 3; 8; 2))\n    8\n\n    # And you can also use it with Bracket syntax\n    iex\u003e (blue [OptionParser.parse, \u0026rest, \"velvet.bv\"])\n    {[], [\"velvet.bv\"], []}\n\n    \n```\n\n\nFor example `Kernel.apply/2` takes a function and a list of arguments\nto apply to it.\n\n    \n```elixir\n\n    iex\u003e (blue (apply; fn x -\u003e x end; [99]))\n    99\n\n    iex\u003e (blue (apply\n    ...\u003e    fn x, y -\u003e x * y end\n    ...\u003e    \u0026rest\n    ...\u003e    12\n    ...\u003e    2))\n    24\n    \n```\n\n\nActually many functions in Elixir take a keyword as last argument, most\ncommonly for options. In these cases it's better to use Bracket LISP\nas it's much easy to use with keywords.\n\n    \n```elixir\n\n    # same as: OptionParser.parse([\"-v\", \"-v\"], [aliases: [v: :verbose], strict: [verbose: :count]])\n    iex\u003e (blue [\n    ...\u003e   OptionParser.parse,\n    ...\u003e   \u0026rest, \"-v\", \"-v\",\n    ...\u003e   \u0026rest, aliases: [v: :verbose], strict: [verbose: :count]\n    ...\u003e ])\n    {[verbose: 2], [], []}\n\n    \n```\n\n### The `:reduce` form\n\nCan be used to apply 2-arity functions or operators in a lisp-like way.\n\n    \n```elixir\n\n    # will expand to ((1 + 2) + 3) at compile time\n    iex\u003e (blue [:reduce, :+, 1, 2, 3])\n    6\n\n    # when used with Elixir's pipe operator\n    iex\u003e (blue (:reduce\n    ...\u003e   :|\u003e\n    ...\u003e   0..5\n    ...\u003e   Stream.map(fn x -\u003e x * x  end)\n    ...\u003e   Enum.reduce(\u0026+/2)\n    ...\u003e   to_string\n    ...\u003e ))\n    \"55\"\n    \n```\n\n\n### :pipe\n\nSince piping is so common in Elixir `:pipe` is a shortcut for `[:reduce, :|\u003e, ...]`\n\n    \n```elixir\n\n    iex\u003e (blue (:pipe\n    ...\u003e   0..5\n    ...\u003e   Stream.map(fn x -\u003e x * x  end)\n    ...\u003e   Enum.reduce(\u0026+/2)\n    ...\u003e   to_string\n    ...\u003e ))\n    \"55\"\n    \n```\n\n\n### Blocks strike back\n\nSince normal block syntax is used as function application inside BLUE LISP, the only way to\nacutally create a block of multiple expressions is by using the `progn` form.\n\n    \n```elixir\n\n    iex\u003e (blue (progn\n    ...\u003e    (a = 3 * 4)\n    ...\u003e    (min; 20; a)\n    ...\u003e ))\n    12\n    \n```\n\n\n### under`_`lisp\n\n`_` is a convenience that comes handy when using common Elixir forms\n\n    \n```elixir\n\n    iex\u003e (blue _(if, 1 \u003c 2, do: 22))\n    22\n\n    # if you use Blocks you need to actually write the keyword brackets\n    iex\u003e (blue (if ; 1 \u003c 2 ; [do: 22]))\n    22\n\n    # if you use Brackets you need to use \u0026rest to capture the keyword tuples\n    iex\u003e (blue [if, 1 \u003c 2, \u0026rest, do: 22])\n    22\n    \n```\n\n\n\n## `use Blue` on `.ex` files.\n\nSince BLUE programs use only valid Elixir syntax, you can write LISP programs on `ex` files.\nThe `mix format` tool however will not play nicely with lispy aesthetics.\n\nAs an example, see `blue_test.exs` file.\n\n    \n```elixir\n\n    use Blue, do: (progn\n      _(defmodule BlueTest, do: (progn\n        (use ExUnit.Case)\n        (doctest Blue)\n      )))\n\n    \n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvic%2Fblue","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvic%2Fblue","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvic%2Fblue/lists"}