Fl4m3Ph03n1x

Fl4m3Ph03n1x

Witchcraft to get something similar to the IO Monad (in Haskell, Scala, etc) but in Elixir?

Background

I have recently been delving into more functional code. My objective right now is to get something similar to the IO Monad (in Haskell, Scala, etc) but in Elixir.

To this extent, I understand Witchcraft should be in theory capable of doing it.

Doubts

However, after reading through their documentation I have some questions:

  • I was not able to find a clear-cut example of the IO Monad. I have the idea what I have to create Monads myself using one of the sub-libraries, but I am not 100% sure of this.
  • I am not sure if Dialzyer plays nice with Witchcraft and if it can detect issues if my code is incorrect (like Scala compiler does).

Could someone help me answer these questions?

Most Liked

lpil

lpil

Creator of Gleam

It’s more the other way around. The static type system makes the IO monad and those checks possible.

Elixir doesn’t yet have a robust static type system so you cannot statically prove properties of your program. There’s work on adding types and other forms of static analysis to Elixir but today you’ll need to look at other BEAM languages such as Gleam or Purerl.

It looks like Witchcraft focuses on the polymorphism aspect of type classes rather than the static verification.

The IO monad only tracks side effects and ordering, so it’s not enough to get that property. You need the more general tool of a robust static type system.

For specifically side effects I think algebraic effects would fit well with Elixir as they are easier to use, have less runtime cost, and map well only existing Elixir code. They don’t do ordering but in a strictly evaluated language that is unimportant.

Macros make implementing a type system more challenging but it’s not a show-stopper, it is still possible.

If you are happy with the level of analysis that Dialyzer offers you then you can implement an IO monad in Elixir without too much pain!

defmodule IOMonad do
  @opaque io(a) :: %__MODULE__{__effect__: (-> a)}
  defstruct :__effect__

  @spec pure((-> a)) :: io(a)
  def pure(effect) do
    %__MODULE__{__effect__: effect}
  end

  @spec map(io(a), (a -> b)) :: io(b)
  def map(io, transform) do
    pure(fn -> transform.(io.__effect__.()))
  end

  @spec bind(io(a), (a -> io(b))) :: io(b)
  def bind(io, transform) do
    pure(fn ->
      transform.(io.__effect__.()).__effect__.()
    end)
  end
end

The same rules apply as in Haskell:

  1. You must wrap all side effecting code in the IO monad rather than performing it immediately.
  2. You must never access __effect__ anywhere in your code, you must always use map and bind.

This unfortunately will be very challenging in Elixir. Unlike in Haskell there is little to verify you are using it correctly, and you’ll have to fork or wrap any libraries you use that have side effects, including the standard library.

Algebraic effects could be used with existing Elixir code without modification but require a more powerful static analysis tool than exists for Elixir today.

edit

As a bonus here’s the same thing in Gleam. The nice thing about this is that the compiler will check that you use it correctly!

pub opaque type Io(a) {
  Io(effect: fn() -> a)
}

pub fn pure(effect) {
  Io(effect)
}

pub fn map(io: Io(a), transform: fn(a) -> b) -> Io(b) {
  Io(fn() { transform(io.effect()) })
}

pub fn bind(io: Io(a), transform: fn(a) -> Io(b)) -> Io(b) {
  Io(fn() { transform(io.effect()).effect() })
}
msimonborg

msimonborg

:eyes: but I thought…

lpil

lpil

Creator of Gleam

Gradient/Gradualizer would do much better! I’m not sure how complete it is but I’m quite excited for it. Looks great.

It’s more of a type checker or compiler feature than a library. The nice thing about it is that for just inferring and restricting effects you don’t need to change the code at all.

Here’s some normal Elixir code

defmodule Main do
  def main do
    text = IO.gets("What's your name?")
    IO.puts("Hello, " <> name)
  end
end

Here it is with an IO monad

defmodule Main do
  def main do
    IOMonad.pure(fn -> IO.gets("What's your name?") end)
    |> IOMonad.map(fn name -> IO.puts("Hello " <> name) end)
    |> IOMonad.unsafe_perform_io()
  end
end

And here it is with algebraic effects.

defmodule Main do
  def main do
    text = IO.gets("What's your name?")
    IO.puts("Hello, " <> name)
  end
end

There’s no changes from the normal code to use IO with this system! All you need to do is annotate functions with any effects they emit.

defmodule MyApp do
  @effects [:console]
  def print_string(string) do
    IO.puts(string)
  end

  @effects [:send_message, :receive_message]
  def run do
    send(self(), "Hello")
    receive do
      x -> x
    end
  end
end

Any functions that call these functions will automatically be detected as also having these effects.

They will be approximately the same. A gradual type system with full annotations should be as sound as Gleam’s type system (with or without annotations) though it comes down to the details of Gradualizer specifically.

Thank you for your support :purple_heart:

The Gleam discord server is often a good place to chat about Gleam or to ask questions. It is quite active these days

Where Next?

Popular in Questions Top

sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
Kurisu
For example for a current url like http://localhost:4000/cosmetic/products?_utf8=✓&amp;query=perfume&amp;page=2, I would like to get: ...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lists...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
JulienCorb
I am trying to implement my new.html.eex file to create new posts on my website. new.html.eex: &lt;h1&gt;Create Post&lt;/h1&gt; &lt;%= ...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New

Other popular topics Top

aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 42158 114
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
klo
Got a question about when to concat vs. prepending items to list then reversing to achieve appending. So i know lists boil down to [1 | ...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
Qqwy
Update: How to use the Blogs &amp; Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 127536 1222
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New

We're in Beta

About us Mission Statement