Skip to content

Instantly share code, notes, and snippets.

@CarlOlson
Last active March 1, 2016 06:53
Show Gist options
  • Save CarlOlson/dca7439f91d14db4075c to your computer and use it in GitHub Desktop.
Save CarlOlson/dca7439f91d14db4075c to your computer and use it in GitHub Desktop.
defmodule Defs do
defmacro defs({name, _, _}, do: entries)
when length(entries) > 0 do
entries
|> Enum.map(&parse_entry(name, &1))
|> Enum.map(&create_def/1)
|> concat_quoted
end
defmacro defps({name, _, _}, do: entries)
when length(entries) > 0 do
entries
|> Enum.map(&parse_entry(name, &1))
|> Enum.map(&create_defp/1)
|> concat_quoted
end
defmacro adefs({name, _, _}, do: entries)
when length(entries) > 0 do
entries
|> Enum.map(&parse_entry(name, &1))
|> Enum.map(&(process_anaphoric &1, name))
|> Enum.map(&create_def/1)
|> concat_quoted
end
defp process_anaphoric({definition, body}, name) do
body = Macro.postwalk(body, fn
{:r, context, args} when is_list(args) ->
{name, context, args}
other -> other
end)
{definition, body}
end
def create_def({definition, body}) do
quote do
Kernel.def(unquote(definition)) do
unquote(body)
end
end
end
def create_defp({definition, body}) do
quote do
Kernel.defp(unquote(definition)) do
unquote(body)
end
end
end
defp parse_entry(name, {:->, _, [[{:when, _, args}], body]}) do
{args, [guard]} = Enum.split(args, -1)
definition = {:when, [],
[{name, [], args}, guard]}
{definition, body}
end
defp parse_entry(name, {:->, _, [args, body]}) do
definition = {name, [], args}
{definition, body}
end
defp concat_quoted([x | xs]), do: concat_quoted(xs, x)
defp concat_quoted([], acc), do: acc
defp concat_quoted([x | xs], acc) do
concat_quoted(
xs,
quote do
unquote(acc)
unquote(x)
end)
end
end
defmodule Test do
import Defs, only: [adefs: 2, defs: 2, defps: 2]
defs fib do
0 -> 1
1 -> 1
n -> fib(n - 1) + fib(n - 2)
end
def reverse(list), do: reverse(list, [])
defps reverse do
[], acc -> acc
[head | tail], acc -> reverse(tail, [head | acc])
end
adefs triangle do
n when n <= 0 -> :error
1 -> 1
n -> r(n - 1) + n
end
end
IO.write "First 10 Fibonacci numbers: "
0..9
|> Enum.map(&Test.fib/1)
|> Enum.join(", ")
|> IO.puts
IO.write "1 to 10 reversed: "
1..10
|> Enum.to_list
|> Test.reverse
|> Enum.join(", ")
|> IO.puts
IO.write "First 10 Triangular numbers: "
1..10
|> Enum.map(&Test.triangle/1)
|> Enum.join(", ")
|> IO.puts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment