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.

Summary

Functions

generate_step(trigger, body, debug, model_name)
reductions(opts \\ [], list) (macro)
update_model(model, list)