Last active
June 16, 2019 15:03
-
-
Save Lakret/11ee741d2e2f96ff56bef11d77dd6ca3 to your computer and use it in GitHub Desktop.
Recursive variable inlining in a macro
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule F do | |
@moduledoc """ | |
Defines a macro that converts recursive 2-tuples to 3-tuples with the third | |
element being a sum of the first 2. Supports variable interpolation at any level | |
of nesting. | |
""" | |
defmacro f(quoted) do | |
inner(quoted) | |
end | |
def inner({x, y}) when is_number(x) and is_number(y) do | |
Macro.escape({x, y, x + y}) | |
end | |
def inner({x, y}) when is_tuple(x) and is_tuple(y) do | |
ds = {inner(x), inner(y)} | |
quote do | |
unquote(ds) | |
end | |
end | |
def inner({x, y}) do | |
quote bind_quoted: [x: x, y: y] do | |
{x, y, x + y} | |
end | |
end | |
def inner(q), do: q | |
end | |
import F | |
iex> x = 15 | |
iex> F.f({1, 2}) | |
{1, 2, 3} | |
iex> F.f({1, x}) | |
{1, 15, 16} | |
iex> F.f({{1, 2}, {3, 4}}) | |
{{1, 2, 3}, {3, 4, 7}} | |
iex> F.f({{1, x}, {3, 4}}) | |
{{1, 15, 16}, {3, 4, 7}} | |
iex> F.f({{1, 2}, {{x, 4}, {5, x}}}) | |
{{1, 2, 3}, {{15, 4, 19}, {5, 15, 20}}} | |
iex> Macro.expand_once( | |
quote do | |
F.f({{1, 2}, {{x, 4}, {5, x}}}) | |
end, | |
__ENV__ | |
) |> Macro.to_string() |> IO.puts() | |
{{1, 2, 3}, {( | |
x = x | |
y = 4 | |
{x, y, x + y} | |
), ( | |
x = 5 | |
y = x | |
{x, y, x + y} | |
)}} | |
:ok |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment