Skip to content

Instantly share code, notes, and snippets.

@polvalente
Created November 8, 2020 03:51
Show Gist options
  • Save polvalente/87943d97536564f91fe651af961a1aaf to your computer and use it in GitHub Desktop.
Save polvalente/87943d97536564f91fe651af961a1aaf to your computer and use it in GitHub Desktop.
Closures in Elixir (almost)
defmodule Incrementer do
@moduledoc """
We need to define this macro separately so we have a fully-qualified name
to call it in a stable manner. Otherwise, the module would have to recursively
(and infinitely) define this macro, which would in turn define the module itself.
"""
defmacro gen_module(value, state_holder_module_name) do
quote bind_quoted: [value: value, state_holder_module_name: state_holder_module_name] do
defmodule state_holder_module_name do
require Incrementer
@value value
def count() do
next = @value + 1
Incrementer.gen_module(next, unquote(state_holder_module_name))
next
end
def get_value, do: @value
end
end
end
end
defmodule ConfigureCounter do
@moduledoc """
The module pair defined in this file setups a counter
using nothing but module definition state in the BEAM.
## Example:
iex(1)> count = ConfigureCounter.setup(MyCounter, 10)
&MyCounter.count/0
iex(2)> count.()
11
iex(3)> count.()
12
iex(4)> count.()
13
iex(5)> count.()
14
iex(6)> count.()
15
iex(7)> count.()
16
iex(8)> count.()
17
iex(9)> MyCounter.get_value
17
"""
require Incrementer
def setup(state_holder_module_name, initial_value) do
Code.compiler_options(ignore_module_conflict: true)
{:module, module_name, _, _} = Incrementer.gen_module(initial_value, state_holder_module_name)
&module_name.count/0
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment