diet v0.1.0 Diet.Transformations
We define a high-level macro, transforms. It takes a do-block
containing a list of a -> b expressions (just like cond or
case).
Each entry in this list represents a reduction. The left hand side specifies a pattern that must be matched , and the right hand side gives the transformation to the model (if any) and then returns the new trigger.
defmodule RLE do
use Diet.Transformations
transforms do
{ :rle, {[], result} } ->
{:done, result |> Enum.reverse}
{ :rle, {[ {a, n}, a | tail], result }} ->
{:rle, {[{a, n+1} | tail], result}}
{ :rle, {[ a, a | tail ], result } } ->
{:rle, {[{a, 2} | tail], result }}
{ :rle, {[a | tail ], result } } ->
{:rle, {tail, [a | result] }}
{ :rle, list } ->
{:rle, {list, []}}
end
end
In the RLE example, the atom :rle is actually not needed at the
fron of each tuple.
Internals
Each transform is converted into a function called step. This
function takes the lhs of the transform and the
model, wrapped in a tuple. So the first transform becomes something like:
def step({{ :encode, string }, model}) do
val = { :rle, { String.codepoints(string), [] } }
case val do
{ :update_model, model, result } ->
{ :continue, result, model }
result ->
{ :continue, result, unquote({:model, [], nil}) }
end
end
So! you cry. What’s with the :update_model?
If a transform needs to update the model, it has to signal the fact by ending the transform code with
update_model(new_model_value) do
«return value»
end
The update_model function then returns a tuple starting
:update_model, which tells the step code to replace the model with
the new value when it returns.