Created
November 8, 2020 03:51
-
-
Save polvalente/87943d97536564f91fe651af961a1aaf to your computer and use it in GitHub Desktop.
Closures in Elixir (almost)
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 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