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:
getting ‘map’, ‘flat_map’, ‘apply’ for free at first, the behaviour of the final result just depends on how you interpret it later.
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.
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?
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.
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.
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.
I do have a couple of suggestions for the codebase:
Add @types and @typespecs for the functions
Rename Freer.Runes.lift?/1 to lift/1 since it does not return a boolean
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
Thank you for the link! This is by far the best explanation of these concepts I’ve read.
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.
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.
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.