A Freer Monad implemented in elixir

Hi all,
I just wrote an elixir library provides a Freer Monad:

With this library, I’m trying to explore the possibility to do something similar to the Haxl.

The key point is to write your monadic logic and business without actually building your Monad first.

With this library we can:

  1. getting ‘map’, ‘flat_map’, ‘apply’ for free at first, the behaviour of the final result just depends on how you interpret it later.
  2. getting a ‘runes’ macro, which enables us to write code similar to for and with that not only on ‘List’ or ‘Matching’ but actually applies to any kind of Monads

Here is a bite of it:

f = Freer.charm do
  runes x <- [1,3,5],
        y <- [2,4,6],
        do: x * y
end
interpreter = Freer.interpret(&([&1]), &Enum.flat_map/2)
interpreter.(f)
#[2, 4, 6, 6, 12, 18, 10, 20, 30]

For more example and explanation, you may take a look at the README on Github.

Feed back needed! please tell me your idea on it!

9 Likes

Excuse my ignorance, but why is this useful? I hardly can tell you what a monad is, much less a Free and Freer Monad. Something about effect interpreters? By using this library, will I be able to overcome some gristly problem in plain Elixir? Can you give a real-world use case?

2 Likes

Thanks for your feed back!

I don’t have too much examples in Elixir yet :frowning:

However, the idea of this library can be found here:

Take the example of Facebook’s Haxl and Twitter’s Stitch. Both systems solve a problem faced by companies that have aggressively adopted a service oriented architecture:1 service orchestration.

Note that Haxl and Stich are implemented in different languages, but shared the same idea: Monads and Interpreters.

This repo is not another Haxl, It’s rather the foundation blow Haxl(in Elixir), and beside composing services, I believe there are more places we can use it.

3 Likes

Monads itself are all about composition of computations, the idea is similar to what with gives us in elixir, but with even more flexibility.

I don’t want to try to explain monads any further (neither the mathematical nor the FP view on them), since it might get rather complex then. There are many explanations on the internet which are covering one of the two views at them, and some are better, some are worse. Just google around and find the one that suits you.

Also I have to say, that most might have used monads (or something similar) without even recognizing it, as I said, with is very similar in its idea. But when they used them, it might been only the idea of it, without special syntax or functional support. That’s exactly the cause why there are so blog posts around, that are named “You could have invented monads” or similar titles. Most of them start with a very basic type and function on that type and increase complexity of both until we have something, that is very nasty to work with. Then there are abstractions made until we have something that is really a monad. Following such a post in a language one is comfortable with, might really give a good start in understanding monads. But I have to admit, all articles of that kind that I did already read were either covering Haskell, ML or F#.

The “free” in “free monads” claims to make creation of monad-types easier by providing the manyfold functions you need to implement for a proper monad (including “base classes” there are about 10 to 15 functions to implement, as well as about the same numbers of “laws” to fullfil) to less than a handfull. But I haven’t so far looked into free monads, since I hadn’t the need to create my own kind of monad so far, but have only used the monads that were already there.

4 Likes

Monads are good for example for nested error handling.
This maybe is more clear in strict typed languages like Scala, Haskell.

Example from

This provides a monadic system for Elixir, a Ruby-flavored language for the Erlang VM.

When dealing with Erlang libraries, several common patterns emerge:

case Library.might_fail() do
    {:ok, value} ->
        case Library.also_might_fail(value) do
            {:ok, something} ->
                some_pid <- {:ok, something}
            {:error, reason} ->
                some_pid <- {:error, reason}
        end
    {:error, reason} ->
        some_pid <- {:error, reason}
end

By stealing the marvelous idea of Monads from the more mainstream functional languages, you can abstract out that tree like this:

import Monad
import ErrorM

some_pid <- (monad ErrorM do
    value <- Library.might_fail()
    Library.also_might_fail(value)
end)
Wasn't that easy?

So in this example you chain functions than can throw error or return result. At the end you will get Monad with result or error.

4 Likes

Thank you for the helpful responses. I learned a lot from the Twitter Stitch video which explained the real-world use case. I am pretty familiar with with now but I didn’t realize it is solving the same type of problem as a monad. I will continue my reading…

My takeaway is that if with becomes too constrictive in terms of interpreting function results - especially from asynchronous tasks - I can consider the flexibility and code readability afforded by free or freer monads.

@lingoer: Thanks for sharing your library. I’ll have a closer look through the code now and see what I can learn.

4 Likes

This is nice introduction Functors, Applicatives, And Monads In Pictures

4 Likes

I do have a couple of suggestions for the codebase:

  1. Add @types and @typespecs for the functions
  2. Rename Freer.Runes.lift?/1 to lift/1 since it does not return a boolean
  3. Structure unit tests as setup-(do the thing)-assert with line breaks in-between for clarity

Adding types would improve the readability of the code and may improve the correctness of your implementation if dialyzer reveals bugs. Number 2 is Elixir convention along with the other function name mark, !. And the last one is just a style which I think improves readability.

Thanks for sharing your library! I learned a lot :grin:

Thank you for the link! This is by far the best explanation of these concepts I’ve read.

3 Likes

Thanks for these suggestions!
I’ll take a look into these problems and fix them later. I’ll also seeking for more conventions and style guides to improve it.

2 Likes

You can run the code through credo for conventions and style improvements. It implements its own style guide so you can take a look at its source code for Elixir-y goodness.

3 Likes

I think Free Monads are super interesting - anyone else have any thoughts, vis-a-vis Elixir?

1 Like

Yes, free monads are very interesting. There’s even a (half-assed) elixir implementation of a limited free monad in widespread use in the Elixir community - Ecto.Multi.

It doesn’t expose the moandic bind and return functions directly. new is more like a monoidal mempty (in Haskell parlance), internally there’s also an add_operation function that is more-or-less like bind. Finally the accumulated state is interpreted when you pass the multi to repo using the __apply__ function.

I’m sure it probably doesn’t strictly satisfy all the moandic laws, but it’s definitely based on the idea of free monads. It was one of the inspirations when I was implementing Ecto.Multi.

5 Likes

Free is pretty amazing.

This is one of the best explanations of why or how you might use Free:
(demos in Purescript but the concept is mathematical)

6 Likes