nitram

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

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. :slight_smile:

Qqwy

Qqwy

TypeCheck Core Team

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

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 :smiley: (sorry If I miss something obvious, I’m just learning those concepts)

nitram

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

Where Next?

Popular in Questions Top

vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
Werner
Hi, I’m using Ubuntu 18.04 and after updating to OTP-24.0 yesterday i have this warning when I run “mix local.hex”: 14:57:30.512 [warn] ...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
Codball
Mix format works fine if run from the cmd. I’ve followed this to facilitate the implementation into VSC which involves downloading an ext...
New
Mooodi
Given a string, how can I get access to its character by index? Enum.at("my_string", 2) doesn't work. Or rather, not char, but a substr...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New

Other popular topics Top

dotdotdotPaul
Okay, I'm having a heck of a time trying to figure out how to best handle the validation of belongs_to associations in Ecto. I'm sure I'...
New
William
I would like to know that is there any online source for learning Phoenix Framework for building E-Commerce Store? Any advantage on build...
New
malloryerik
Hi, this is for people who, like me, have had some friction using .html.heex templates in VSCode. The solution seems to be, in a hyphena...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
mgjohns61585
Could someone help me? I'm making my first elixir program, number guessing game. I can't figure out how to convert the user's guess from ...
New
danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 27727 240
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
AstonJ
by Lance Halvorsen Elixir and Phoenix are generating tremendous excitement as an unbeatable platform for building modern web application...
460 27162 124
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

We're in Beta

About us Mission Statement