plymio_vekil v0.1.0 Plymio.Vekil.Forom.List View Source
The module implements the Plymio.Vekil.Forom protocol and manages a list of other forom
See Plymio.Vekil.Forom for the definitions of the protocol functions.
See Plymio.Vekil for an explanation of the test environment.
Module State
See Plymio.Vekil.Forom for the common fields.
The default :produce_default is an empty list.
The default :realise_default is an empty list.
The module’s state is held in a struct with the following field(s):
| Field | Aliases | Purpose |
|---|---|---|
:forom | holds the list of child forom |
Link to this section Summary
Functions
new/1 takes an optional opts and creates a new forom returning {:ok, forom}
normalise/1 creates a new forom from its argument unless the argument is already one
produce/2 takes a forom and an optional opts
realise/2 takes a forom and an optional opts, calls
produce/2, and then gets (Keyword.get_values/2) the :forom key values
Link to this section Types
Link to this section Functions
new/1 takes an optional opts and creates a new forom returning {:ok, forom}.
Examples
iex> {:ok, forom} = new()
...> match?(%FOROMLIST{}, forom)
true
Plymio.Vekil.Utility.forom?/1 returns true if the value implements Plymio.Vekil.Forom
iex> {:ok, forom} = new()
...> forom |> Plymio.Vekil.Utility.forom?
true
The list is passed using the :forom key:
iex> {:ok, forom1} = FOROMFORM.new(forom: quote(do: x = x + 1))
...> {:ok, forom} = new(forom: forom1)
...> forom |> Plymio.Vekil.Utility.forom?
true
iex> {:ok, forom} = new(
...> forom: [
...> FOROMTERM.new!(forom: 42),
...> FOROMFORM.new!(forom: quote(do: x = x * x * x)),
...> FOROMPROXY.new!(forom: :x_sub_1),
...> ])
...> forom |> Plymio.Vekil.Utility.forom?
true
normalise/1 creates a new forom from its argument unless the argument is already one.
The function tries to make it as as convenient as possible to create a new forom, making some assumptions and may not return a list forom.
If the argument is a list, each element is treated as below and the created forom uses to create a list forom.
If an atom is found, a Plymio.Vekil.Forom.Proxy is created.
If the argument is a valid form (Macro.validate/1) a new Plymio.Vekil.Forom.Form is created.
Any other argument creates a Plymio.Vekil.Forom.Term.
Examples
Here a form is recognised:
iex> {:ok, %FOROMFORM{} = forom} = quote(do: x = x + 1) |> normalise
...> {:ok, {form, _}} = forom |> FOROMPROT.realise
...> form |> harnais_helper_test_forms!(binding: [x: 6])
{7, ["x = x + 1"]}
Here the argument is an atom and a proxy forom is created. Note a vekil is needed to resolve the proxy.
iex> {:ok, %FOROMPROXY{} = forom} = :x_mul_x |> normalise
...> realise_opts = [vekil: vekil_helper_form_vekil_example1()]
...> {:ok, {form, _}} = forom |> FOROMPROT.realise(realise_opts)
...> form |> harnais_helper_test_forms!(binding: [x: 3])
{9, ["x = x * x"]}
A list of atoms works. Note the returned forom is a list forom.
iex> {:ok, %FOROMLIST{} = forom} = [:x_add_1, :x_mul_x, :x_sub_1] |> normalise
...> realise_opts = [vekil: vekil_helper_form_vekil_example1()]
...> {:ok, {form, _}} = forom |> FOROMPROT.realise(realise_opts)
...> form |> harnais_helper_test_forms!(binding: [x: 7])
{63, ["x = x + 1", "x = x * x", "x = x - 1"]}
A mixture works:
iex> {:ok, %FOROMLIST{} = forom} = [
...> 42,
...> quote(do: x = x * x * x),
...> :x_sub_1
...> ] |> normalise
...> realise_opts = [vekil: vekil_helper_form_vekil_example1()]
...> {:ok, {values, _}} = forom |> FOROMPROT.realise(realise_opts)
...> values |> harnais_helper_show_forms
{:ok, ["42", "x = x * x * x", "x = x - 1"]}
The other examples don’t really highlight that the child forom of a list forom can themselves be list forom.
iex> {:ok, forom1} = [:x_sub_1, :x_add_1, :x_mul_x] |> normalise
...> {:ok, forom2} = [
...> quote(do: x = x + 9),
...> quote(do: x = x - 5),
...> quote(do: x = x * x * x),
...> ] |> normalise
...> {:ok, forom3} = :x_funs |> normalise
...> {:ok, forom} = [forom1, forom2, forom3] |> normalise
...> realise_opts = [vekil: vekil_helper_form_vekil_example1()]
...> {:ok, {forms, _}} = forom |> FOROMPROT.realise(realise_opts)
...> forms |> harnais_helper_test_forms!(binding: [x: 3])
{4831203, ["x = x - 1", "x = x + 1", "x = x * x",
"x = x + 9", "x = x - 5", "x = x * x * x",
"x = x + 1", "x = x * x", "x = x - 1"]}
Anything else creates a term forom:
iex> {:ok, %FOROMTERM{} = forom} = %{a: 1} |> normalise
...> {:ok, {value, _}} = forom |> FOROMPROT.realise
...> value
%{a: 1}
produce/2 takes a forom and an optional opts.
It calls produce/2 on each of the forom’s children and merges
their products into a single Keyword returning {:ok, {product, forom}}
Examples
Here the list contains integers:
iex> {:ok, forom} = new(
...> forom: [
...> FOROMTERM.new!(forom: 7),
...> FOROMTERM.new!(forom: 33),
...> FOROMTERM.new!(forom: 2),
...> ])
...> {:ok, {product, %FOROMLIST{}}} = forom |> FOROMPROT.produce
...> product |> Keyword.get_values(:forom) |> Enum.sum
42
Here the list contains code snippets:
iex> {:ok, forom} = [forom: [
...> FOROMFORM.new!(forom: quote(do: x = x + 1)),
...> FOROMFORM.new!(forom: quote(do: x = x * x)),
...> FOROMFORM.new!(forom: quote(do: x = x - 1))
...> ]] |> FOROMLIST.new
...> {:ok, {product, _}} = forom |> FOROMPROT.produce
...> product |> Keyword.get_values(:forom)
...> |> harnais_helper_test_forms!(binding: [x: 3])
{15, ["x = x + 1", "x = x * x", "x = x - 1"]}
As an aside, and same example, normalise/1 helps reduce the boilerplace:
iex> {:ok, forom} = [
...> quote(do: x = x + 1),
...> quote(do: x = x * x),
...> quote(do: x = x - 1)
...> ] |> normalise
...> {:ok, {product, _}} = forom |> FOROMPROT.produce
...> product |> Keyword.get_values(:forom)
...> |> harnais_helper_test_forms!(binding: [x: 3])
{15, ["x = x + 1", "x = x * x", "x = x - 1"]}
A similar example to the one above but the list contains proxy foroms which are recursively produced. Note the proxy foroms need a vekil to resolve the proxies.
iex> {:ok, forom} = [forom: [
...> FOROMPROXY.new!(forom: :x_add_1),
...> FOROMPROXY.new!(forom: :x_mul_x),
...> FOROMPROXY.new!(forom: :x_sub_1)
...> ]] |> FOROMLIST.new
...> produce_opts = [vekil: vekil_helper_form_vekil_example1()]
...> {:ok, {product, _}} = forom |> FOROMPROT.produce(produce_opts)
...> product |> Keyword.get_values(:forom)
...> |> harnais_helper_test_forms!(binding: [x: 3])
{15, ["x = x + 1", "x = x * x", "x = x - 1"]}
An empty forom does not produce any :forom keys so the :produce_default value is returned. Here the default :produce_default is an empty list.
iex> {:ok, forom} = new()
...> {:ok, {product, _}} = forom |> FOROMPROT.produce
...> product |> Keyword.get_values(:forom)
[]
Same example but the :produce_default value is set:
iex> {:ok, forom} = new()
...> {:ok, {product, _}} = forom
...> |> FOROMPROT.produce(produce_default: [forom: 1, forom: :due, forom: "tre"])
...> product |> Keyword.get_values(:forom)
[1, :due, "tre"]
realise/2 takes a forom and an optional opts, calls
produce/2, and then gets (Keyword.get_values/2) the :forom key values.
The example are essentially the same as produce/2
Examples
iex> {:ok, forom} = new(
...> forom: [
...> FOROMTERM.new!(forom: 7),
...> FOROMTERM.new!(forom: 33),
...> FOROMTERM.new!(forom: 2),
...> ])
...> {:ok, {values, %FOROMLIST{}}} = forom |> FOROMPROT.realise
...> values |> Enum.sum
42
iex> {:ok, forom} = [forom: [
...> FOROMFORM.new!(forom: quote(do: x = x + 1)),
...> FOROMFORM.new!(forom: quote(do: x = x * x)),
...> FOROMFORM.new!(forom: quote(do: x = x - 1))
...> ]] |> FOROMLIST.new
...> {:ok, {forms, _}} = forom |> FOROMPROT.realise
...> forms |> harnais_helper_test_forms!(binding: [x: 3])
{15, ["x = x + 1", "x = x * x", "x = x - 1"]}
iex> {:ok, forom} = [forom: [
...> FOROMPROXY.new!(forom: :x_add_1),
...> FOROMPROXY.new!(forom: :x_mul_x),
...> FOROMPROXY.new!(forom: :x_sub_1)
...> ]] |> FOROMLIST.new
...> realise_opts = [vekil: vekil_helper_form_vekil_example1()]
...> {:ok, {forms, _}} = forom |> FOROMPROT.realise(realise_opts)
...> forms |> harnais_helper_test_forms!(binding: [x: 3])
{15, ["x = x + 1", "x = x * x", "x = x - 1"]}
iex> {:ok, forom} = [:x_add_1, :x_mul_x, :x_sub_1] |> normalise
...> realise_opts = [vekil: vekil_helper_form_vekil_example1()]
...> {:ok, {forms, _}} = forom |> FOROMPROT.realise(realise_opts)
...> forms |> harnais_helper_test_forms!(binding: [x: 3])
{15, ["x = x + 1", "x = x * x", "x = x - 1"]}
iex> {:ok, forom} = new()
...> {:ok, {values, _forom}} = forom |> FOROMPROT.realise
...> values
[]
update/2 implements Plymio.Vekil.Forom.update/2.
Examples
iex> {:ok, forom} = new(forom: FOROMTERM.new!(forom: 7))
...> {:ok, forom} = forom |> FOROMPROT.update(
...> forom: [FOROMTERM.new!(forom: 33), FOROMTERM.new!(forom: 2)])
...> {:ok, {values, %FOROMLIST{}}} = forom |> FOROMPROT.realise
...> values |> Enum.sum
35