View Source Algae.Writer (Algae v1.3.2-doma)

Algae.Writer helps capture the pattern of writing to a pure log or accumulated value, handling the bookkeeping for you.

If Algae.Reader is quasi-read-only, Algae.Writer is quasi-write-only. This is often used for loggers, but could be anything as long as the hidden value is a Witchcraft.Monoid.

There are many applications of Writers, but as an illustrative point, one could use it for logging across processes and time, since the log is carried around with the result in a pure fashion. The monadic DSL helps make using these feel more natural.

For an illustrated guide to Writers, see Thee Useful Monads.

anatomy

Anatomy

  %Algae.Writer{writer: {value, log}}
                                
 # "explicit" value position    "hidden" position,
 #                               commonly used as a log

examples

Examples

iex> use Witchcraft
...>
...> excite =
...>   fn string ->
...>     monad writer({0.0, "log"}) do
...>       tell string
...>
...>       excited <- return "#{string}!"
...>       tell " => #{excited} ... "
...>
...>       return excited
...>     end
...>   end
...>
...> {_, logs} =
...>   "Hi"
...>   |> excite.()
...>   >>> excite
...>   >>> excite
...>   |> censor(&String.trim_trailing(&1, " ... "))
...>   |> run()
...>
...> logs
"Hi => Hi! ... Hi! => Hi!! ... Hi!! => Hi!!!"

iex> use Witchcraft
...>
...> exponent =
...>   fn num ->
...>     monad writer({0, 0}) do
...>       tell 1
...>       return num * num
...>     end
...>   end
...>
...> initial = 42
...> {result, times} = run(exponent.(initial) >>> exponent >>> exponent)
...>
...> "#{initial}^#{round(:math.pow(2, times))} = #{result}"
"42^8 = 9682651996416"

Link to this section Summary

Functions

Run a writer, and run a function over the resulting log.

Copy the log into the value position. This makes it accessible in do-notation.

Similar to listen/1, but with the ability to adjust the copied log.

Construct a Algae.Writer struct from a starting value and log.

Run a function in the value portion of an Algae.Writer on the log.

Extract the enclosed value and log from an Algae.Writer.

Set the "log" portion of an Algae.Writer step

Similar to new/2, but taking a tuple rather than separate fields.

Link to this section Types

@type log() :: Witchcraft.Monoid.t()
@type t() :: %Algae.Writer{writer: writer()}
@type value() :: any()
@type writer() :: {value(), log()}

Link to this section Functions

@spec censor(t(), (any() -> any())) :: t()

Run a writer, and run a function over the resulting log.

examples

Examples

iex> 42
...> |> new(["hi", "THERE", "friend"])
...> |> censor(&Enum.reject(&1, fn log -> String.upcase(log) == log end))
...> |> run()
{42, ["hi", "friend"]}

iex> use Witchcraft
...>
...> 0
...> |> new(["logs"])
...> |> monad do
...>   tell ["Start"]
...>   tell ["BANG!"]
...>   tell ["shhhhhhh..."]
...>   tell ["LOUD NOISES!!!"]
...>   tell ["End"]
...>
...>   return 42
...> end
...> |> censor(&Enum.reject(&1, fn log -> String.upcase(log) == log end))
...> |> run()
{42, ["Start", "shhhhhhh...", "End"]}
@spec listen(t()) :: t()

Copy the log into the value position. This makes it accessible in do-notation.

examples

Examples

iex> listen(%Algae.Writer{writer: {42, "hi"}})
%Algae.Writer{writer: {{42, "hi"}, "hi"}}

iex> use Witchcraft
...>
...> monad new(1, 1) do
...>   wr <- listen tell(42)
...>   tell 43
...>   return wr
...> end
%Algae.Writer{
  writer: {{%Witchcraft.Unit{}, 42}, 85}
}
@spec listen(t(), (log() -> log())) :: t()

Similar to listen/1, but with the ability to adjust the copied log.

examples

Examples

iex> listen(%Algae.Writer{writer: {1, "hi"}}, &String.upcase/1)
%Algae.Writer{
  writer: {{1, "HI"}, "hi"}
}
Link to this function

new(value \\ 0, log \\ [])

View Source
@spec new(any(), Witchcraft.Monoid.t()) :: t()

Construct a Algae.Writer struct from a starting value and log.

examples

Examples

iex> new()
%Algae.Writer{writer: {0, []}}

iex> new("hi")
%Algae.Writer{writer: {"hi", []}}

iex> new("ohai", 42)
%Algae.Writer{writer: {"ohai", 42}}
@spec pass(t()) :: t()

Run a function in the value portion of an Algae.Writer on the log.

Notice that the structure is similar to what somes out of listen/{1,2}

Algae.Writer{writer: {{_, function}, log}}

examples

Examples

iex> pass(%Algae.Writer{writer: {{1, fn x -> x * 10 end}, 42}})
%Algae.Writer{writer: {1, 420}}

iex> use Witchcraft
...>
...> monad new("string", ["logs"]) do
...>   a <-  ["start"] |> tell() |> listen()
...>   tell ["middle"]
...>
...>   {value, logs} <- return a
...>   pass writer({{value, fn [log | _] -> [log | [log | logs]] end}, logs})
...>
...>   tell ["next is 42"]
...>   return 42
...> end
%Algae.Writer{
  writer: {42, ["start", "middle", "start", "start", "start", "next is 42"]}
}
@spec run(t()) :: value()

Extract the enclosed value and log from an Algae.Writer.

examples

Examples

iex> run(%Algae.Writer{writer: {"hi", "there"}})
{"hi", "there"}

iex> use Witchcraft
...>
...> half =
...>   fn num ->
...>     monad writer({0.0, ["log"]}) do
...>       let half = num / 2
...>       tell ["#{num} / 2 = #{half}"]
...>       return half
...>     end
...>   end
...>
...> run(half.(42) >>> half >>> half)
{
  5.25,
  [
    "42 / 2 = 21.0",
    "21.0 / 2 = 10.5",
    "10.5 / 2 = 5.25"
  ]
}
@spec tell(log()) :: t()

Set the "log" portion of an Algae.Writer step

examples

Examples

iex> tell("secrets")
%Algae.Writer{writer: {%Witchcraft.Unit{}, "secrets"}}

iex> use Witchcraft
...>
...> monad %Algae.Writer{writer: {"string", 1}} do
...>   tell 42
...>   tell 43
...>   return "hey"
...> end
%Algae.Writer{writer: {"hey", 85}}

iex> use Witchcraft
...>
...> half =
...>   fn num ->
...>     monad writer({0.0, ["log"]}) do
...>       let half = num / 2
...>       tell ["#{num} / 2 = #{half}"]
...>       return half
...>     end
...>   end
...>
...> run(half.(42.0) >>> half >>> half)
{
  5.25,
  [
    "42.0 / 2 = 21.0",
    "21.0 / 2 = 10.5",
    "10.5 / 2 = 5.25"
  ]
}
@spec writer(writer()) :: t()

Similar to new/2, but taking a tuple rather than separate fields.

examples

Examples

iex> writer({"ohai", 42})
%Algae.Writer{writer: {"ohai", 42}}