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]