View Source Witchcraft.Monad (Witchcraft v1.0.6-doma)
Very similar to Chain, Monad provides a way to link actions, and a way
to bring plain values into the correct context (Applicative).
This allows us to view actions in a full framework along the lines of functor and applicative:
data ---------------- function ----------------------------> result
| | |
of(Container, data) of/2, or similar of(Container, result)
↓ ↓ ↓
%Container<data> --- (data -> %Container<updated_data>) ---> %Container<updated_data>As you can see, the linking function may just be of now that we have that.
For a nice, illustrated introduction, see Functors, Applicatives, And Monads In Pictures.
Having of also lets us enhance do-notation with a convenient return function (see monad/2)
type-class
Type Class
An instance of Witchcraft.Monad must also implement Witchcraft.Applicative
and Wicthcraft.Chainable.
Functor [map/2]
↓
Apply [convey/2]
↓ ↓
[of/2] Applicative Chain [chain/2]
↓ ↓
Monad
[_]
Link to this section Summary
Functions
Variant of monad/2 where each step internally occurs asynchonously, but lines
run strictly one after another.
Alias for async_chain/2
Asynchronous variant of Witchcraft.Chain.chain/2.
Asynchronous variant of Witchcraft.Chain.draw/2.
do-notation enhanced with a return operation.
Link to this section Types
@type t() :: any()
Link to this section Functions
Variant of monad/2 where each step internally occurs asynchonously, but lines
run strictly one after another.
examples
Examples
iex> async [] do
...> [1, 2, 3]
...> end
[1, 2, 3]
iex> async [] do
...> [1, 2, 3]
...> [4, 5, 6]
...> [7, 8, 9]
...> end
[
7, 8, 9,
7, 8, 9,
7, 8, 9,
7, 8, 9,
7, 8, 9,
7, 8, 9,
7, 8, 9,
7, 8, 9,
7, 8, 9
]
iex> async [] do
...> Witchcraft.Applicative.of([], 1)
...> end
[1]
iex> async [] do
...> a <- [1,2,3]
...> b <- [4,5,6]
...> return(a * b)
...> end
[
4, 5, 6,
8, 10, 12,
12, 15, 18
]
iex> async [] do
...> a <- return 1
...> b <- return 2
...> return(a + b)
...> end
[3]
@spec async_bind(Witchcraft.Chain.t(), Witchcraft.Chain.link()) :: Witchcraft.Chain.t()
Alias for async_chain/2
@spec async_chain(Witchcraft.Chain.t(), Witchcraft.Chain.link()) :: Witchcraft.Chain.t()
Asynchronous variant of Witchcraft.Chain.chain/2.
Note that each async_chain call awaits that step's completion. This is a
feature not a bug, since chain can introduce dependencies between nested links.
However, this means that the async features on only really useful on larger data sets,
because otherwise we're just sparking tasks and immediaetly waiting a single application.
examples
Examples
iex> async_chain([1, 2, 3], fn x -> [x, x] end)
[1, 1, 2, 2, 3, 3]
iex> async_chain([1, 2, 3], fn x ->
...> async_chain([x + 1], fn y ->
...> [x * y]
...> end)
...> end)
[2, 6, 12]
0..10_000
|> Enum.to_list()
|> async_chain(fn x ->
async_chain([x + 1], fn y ->
Process.sleep(500)
[x * y]
end)
end)
#=> [0, 2, 6, 12, 20, 30, 42, ...] in around a second
@spec async_draw(Witchcraft.Chain.t(), Witchcraft.Chain.link()) :: Witchcraft.Chain.t()
Asynchronous variant of Witchcraft.Chain.draw/2.
Note that each async_draw call awaits that step's completion. This is a
feature not a bug, since chain can introduce dependencies between nested links.
However, this means that the async features on only really useful on larger data sets,
because otherwise we're just sparking tasks and immediaetly waiting a single application.
examples
Examples
iex> async_draw(fn x -> [x, x] end, [1, 2, 3])
[1, 1, 2, 2, 3, 3]
iex> (fn y -> [y * 5, y * 10] end)
...> |> async_draw(fn x -> [x, x] end
...> |> async_draw([1, 2, 3])) # note the "extra" closing paren
[5, 10, 5, 10, 10, 20, 10, 20, 15, 30, 15, 30]
iex> fn x ->
...> fn y ->
...> [x * y]
...> end
...> |> async_draw([x + 1])
...> end
...> |> async_draw([1, 2, 3])
[2, 6, 12]
fn x ->
fn y ->
Process.sleep(500)
[x * y]
end
|> async_draw([x + 1])
end
|> async_draw(Enum.to_list(0..10_000))
[0, 2, 6, 12, ...] # in under a second
do-notation enhanced with a return operation.
return is the simplest possible linking function, providing the correct of/2
instance for your monad.
examples
Examples
iex> monad [] do
...> [1, 2, 3]
...> end
[1, 2, 3]
iex> monad [] do
...> [1, 2, 3]
...> [4, 5, 6]
...> [7, 8, 9]
...> end
[
7, 8, 9,
7, 8, 9,
7, 8, 9,
7, 8, 9,
7, 8, 9,
7, 8, 9,
7, 8, 9,
7, 8, 9,
7, 8, 9
]
iex> monad [] do
...> Witchcraft.Applicative.of([], 1)
...> end
[1]
iex> monad [] do
...> return 1
...> end
[1]
iex> monad [] do
...> monad {999} do
...> return 1
...> end
...> end
{1}
iex> monad [] do
...> a <- [1,2,3]
...> b <- [4,5,6]
...> return(a * b)
...> end
[
4, 5, 6,
8, 10, 12,
12, 15, 18
]
iex> monad [] do
...> a <- return 1
...> b <- return 2
...> return(a + b)
...> end
[3]