nitram
Witchraft combine monads, or where is discussion about witchraft?
Hello everibady,
recently I started experimenting with algae, and I found out that in a lot of cases I need to combine multiple monads. Is there way of do it in this library? Quick search show that in haskell they use something called monad transformers. Is it on the read map, or is there some witchcraft specific trick? Or how would you do it without transformers?
I’m particulary interested in merging State and Writer monads.
Thank you
Most Liked
OvermindDL1
I wonder if @expede exists to be able to ask, hmm I guess not. Maybe it’s worth raising this combination issue on the witchcraft issue tracker? It would be a useful thing to add. 
nitram
Qqwy
To my knowledge, currently there unfortunately isn’t a monad transformer stack implementation for Witchcraft, so you probably have to define them yourself.
An alternative might be to look into ‘effect systems’ and model effectful computations using that instead. (c.f. the Haskell library fused-effects)
nitram
I tried something like this:
monad %Algae.Writer{} do
events <-
monad %Algae.State{} do
events <- get(&create/1)
modify & mutate(&1, events)
return events
end
tell(events)
events <-
monad %Algae.State{} do
events <- get(&increment/1)
modify & mutate(&1, events)
return events
end
tell(events)
end
|>...
But I’m not sure how to run this
(sorry If I miss something obvious, I’m just learning those concepts)
nitram
Well, I don’t have project, I’m experimenting in one file :D, It basicali is mini cqrs system where you have domain functions create, increment, decrement, add that generate events that they should by applied on state using function mutate and I’m triing to create command handler for it using monads (using state to store actual state and after every domain function mutate it and also writer to store all events that been generated during execution, function test() is returning array of solutions, I managed to solve it without writer using chain (function exec2):
defmodule Witch do
use Witchcraft.Monad
use Witchcraft.Chain
import Algae.State
import Algae.Writer
def create(agg) do
if is_nil(agg) do
[:created]
end
end
def increment(agg) do
if agg < 10 do
[{:added, 1}]
end
end
def decrement(agg) do
if agg > 0 do
[{:subsctracted, 1}]
end
end
def add(agg, count) do
if agg < 10 do
[{:added, count}]
end
end
def subsctract(agg, count) do
if agg > 0 do
[{:subsctracted, count}]
end
end
def mutate(_agg, :created) do
0
end
def mutate(agg, {:added, count}) do
agg + count
end
def mutate(agg, {:subsctracted, count}) do
agg - count
end
def mutate(agg, events) when is_list(events) do
Enum.reduce(events, agg, &mutate(&2, &1))
end
def test() do
[
put(1) |> run(0),
modify(& &1 + 1) |> run(0),
get() |> run(0),
get(& create/1) |> run(nil),
monad %Algae.State{} do
events <- get(& create/1)
modify & mutate(&1, events)
nevents <- get(& increment/1)
modify & mutate(&1, nevents)
return events ++ nevents
end
|> evaluate(nil),
monad %Algae.State{} do
events1 <- exec(& create/1)
events2 <- exec(& increment/1)
events3 <- exec(& increment/1)
return events1 ++ events2 ++ events3
end
|> run(nil),
exec1(& create/1) >>> exec2(& increment/1) >>> exec2(& increment/1) |> evaluate(nil),
Witchcraft.Chain.chain do
[]
exec2(& create/1)
exec2(& increment/1)
exec2(& increment/1)
count <- [1, 2, 3]
exec2(& add(&1, count))
end,
monad %Algae.State{} do
exec(& create/1)
exec(& increment/1)
end |> evaluate(nil),
monad %Algae.Writer{} do
events <-
monad %Algae.State{} do
events <- get(&create/1)
modify & mutate(&1, events)
return events
end
tell(events)
events <-
monad %Algae.State{} do
events <- get(&increment/1)
modify & mutate(&1, events)
return events
end
tell(events)
end
|> Algae.Writer.run(),
tell("test"),
new(1, "test") |> listen()
]
end
def exec(callback) do
monad %Algae.State{} do
events <- get(callback)
modify & mutate(&1, events)
return events
end
end
def exec1(callback) do
exec2(callback).([])
end
def exec2(callback) do
fn old ->
monad %Algae.State{} do
events <- get(callback)
modify & mutate(&1, events)
return old ++ events
end
end
end
end








