News for hackers. Stuff that matters.
Re:Are Monads a Waste of Time? by bad_user on Tuesday February 20, 2018 @07:39AM (#16419877)
Monads are not directly related to handling side effects. Or to the famous IO that you're refeering here. What a Monad does is to force sequencing by creating a data dependency.

Speaking of IO ...

In an imperative program you get guaranteed ordering of those instructions, but that ordering is thread local, meaning that the compiler, the runtime, the kernel, the CPU are all free to reorder instructions for optimal execution and ordering between threads is forced via memory barriers, which is in fact incredibly error prone.

In an FP language such as Haskell you get the extra problem that the compiler is even more free to rewrite and execute your code in any order it sees fit due to non-strictness and to referential transparency.

What the IO monad does is to "suspend side effects" and to force ordering on evaluation. And guess what, the IO monad is useful even in your average imperative program for describing concurrent logic.

Here are the implementations I contributed to:

1. https://monix.io/docs/2x/eval/task.html (Scala)

2. https://github.com/typelevel/cats-effect (Scala)

3. https://funfix.org (JavaScript)

If you've ever worked with JS Promises, think of IO as a non-broken, pure, awesome alternative.

And this is just IO. There are other monads as well. List is a monad, Option and Either are monads ;-)

---

I recommend you let go of your misconceptions and do some learning because this is a freaking useful concept.

Re:Are Monads a Waste of Time? by olavk on Tuesday February 20, 2018 @07:50AM (#16419921)
> I recommend you let go of your misconceptions and do some learning

Thank you for the advice! Monads seem to have some kind of smugness creation field.

I know there are other monads beside State and IO, I was specifically referencing the argument in the linked article which was about using monads for mutable state, basically turning the code into imperative style.

Re:Are Monads a Waste of Time? by bad_user on Tuesday February 20, 2018 @08:11AM (#16420022)
That wasn’t smugness. I only replied to you because those were my thoughts from 5 years ago. And I was wrong.

And yes, it’s a little troubling that such awesome concepts are not penetrating the mainstream, being so misunderstood.

I blame the available leaning resources.

It took the GC 30 years after invention to become mainstream. Functional programming, actual functional programming, apparently takes longer than that.

Re:Are Monads a Waste of Time? by AnimalMuppet on Tuesday February 20, 2018 @01:20PM (#16422531)
> That wasn’t smugness.

Maybe not. It was still condescending, though...

Re:Are Monads a Waste of Time? by tome on Tuesday February 20, 2018 @08:23AM (#16420087)
> What a Monad does is to force sequencing by creating a data dependency.

Does it really? Maybe this is another one of those famous misconceptions!

https://hackage.haskell.org/package/tardis-0.4.1.0/docs/Cont...

Re:Are Monads a Waste of Time? by marcosdumay on Tuesday February 20, 2018 @12:19PM (#16421979)
Monads semantics are mostly what is created by bind. And bind is an operation that describes how to sequence expressions.

What you may be misunderstanding is that "sequencing expressions" does not mean "execute one expression after the other". It means, take a sequence of expressions and give it some meaning. Yes, that meaning can be "execute one after the other", or "run everything at the same time", or any other ordering. The meaning can ignore any ordering and only care about some context, or apply some order over the result in an ordered structure, or almost anything else.

Re:Are Monads a Waste of Time? by tome on Tuesday February 20, 2018 @04:27PM (#16424356)
I agree with your characterization, which is not at all equivalent to "What a Monad does is to force sequencing by creating a data dependency".
Re:Are Monads a Waste of Time? by pdpi on Tuesday February 20, 2018 @09:05AM (#16420350)
Nah, it's not really "one of those famous misconceptions".

The crucial detail is that TardisT must wrap a MonadFix, which is used for cyclical data structures. It effectively works not by making time go "backwards", but by making time loop around. It still creates a sequencing relationship.

Re:Are Monads a Waste of Time? by tome on Tuesday February 20, 2018 @09:09AM (#16420373)
> The crucial detail is that TardisT must wrap a MonadFix

So? The non-transformer version can still "read data before it's written". It's very hard to see any form of sequencing in that example.

> It still creates a sequencing relationship.

A sequencing relationship between what exactly?

Re:Are Monads a Waste of Time? by bad_user on Tuesday February 20, 2018 @09:26AM (#16420482)
The sequencing is described precisely in the signature of bind.

    (>>=)
        :: Monad m
        => m a         -- Left argument
        -> (a -> m b)  -- Right argument
        -> m b
You don’t need to explain an individual monad instance to notice that this signature requires “a” in order to generate “m b”.
Re:Are Monads a Waste of Time? by pdpi on Tuesday February 20, 2018 @09:51AM (#16420684)
That's not quite right.

Let's define an operator `|> = (flip $)`, which has a type signature `a -> (a -> b) -> b`, which, by your reasoning, should force sequencing too. Except it doesn't: Laziness is a bitch to work with, and `a |> f |> g` evaluates to `g(f(a))`, and g is evaluated first, which then evaluates f(a) on demand. If you consider `1 |> (+1) |> const 4`, this will evaluate to 4 without ever performing the addition.

Instead, let's compare this to the monadic equivalent. `(return 1) >>= return . (+ 1) >>= return . (const 4)`. The sequence that's being forced here isn't that (+ 1) is evaluated, it's that the `return` in `return 1` is evaluated (producing a 1) before `return . (+ 1)` is ever touched, and that _that_ return is evaluated (presumably producing an unevaluated thunk for (1 + 1)) before `return . (const 4)` is touched.

In IO world, this corresponds to guaranteeing that the IO operations happen in sequence irrespective of the order in which the pure computations they wrap are evaluated in.

Re:Are Monads a Waste of Time? by tome on Tuesday February 20, 2018 @09:57AM (#16420742)
> the `return` in `return 1` is evaluated (producing a 1) before `return . (+ 1)` is ever touched, and that _that_ return is evaluated (presumably producing an unevaluated thunk for (1 + 1)) before `return . (const 4)` is touched.

That's not quite right either. The former returns need never be evaluated.

    > undefined >>= (return . (const 4)) :: Identity Int
    Identity 4
Re:Are Monads a Waste of Time? by pdpi on Tuesday February 20, 2018 @09:59AM (#16420767)
Right — I should've said "that's the mechanism through which the implementation of `>>=` can force sequencing". `>>=` for Identity doesn't, most of the other common ones do, in some sense or another.
Re:Are Monads a Waste of Time? by tome on Tuesday February 20, 2018 @10:03AM (#16420812)
Right! `>>=` can force sequencing. It doesn't for Identity, Writer.Lazy or State.Lazy, but it can. OK, but also Arrow and Monoid can enforce a (different sort of) sequencing relationship.

Neither does monad force a sequencing relationship nor is it the only thing than can force a sequencing relationship so I can only conclude that "What a Monad does is to force sequencing by creating a data dependency" is indeed one of those misconceptions!

Re:Are Monads a Waste of Time? by lmm on Wednesday February 21, 2018 @05:00AM (#16428287)
That's just Haskell's crazy evaluation semantics though, not something that applies to monads in general.
Re:Are Monads a Waste of Time? by tome on Wednesday February 21, 2018 @05:31AM (#16428429)
Indeed. But bad_user made a claim about monads in general ("What a Monad does is to force sequencing by creating a data dependency.") so all I need to do to refute it is give an example of a particular monad where the claim doesn't hold.
Re:Are Monads a Waste of Time? by lmm on Wednesday February 21, 2018 @06:23AM (#16428661)
Monads force a denotation of sequencing. Of course you can write a language implementation where the sequencing of operation does not represent the sequencing of denotation (just as you can write a "compiler" that compiles all programs to Hello World), but, well, that's on you.
Re:Are Monads a Waste of Time? by tome on Wednesday February 21, 2018 @01:08PM (#16431508)
> Monads force a denotation of sequencing

Aha! Now we're on to something.

Re:Are Monads a Waste of Time? by tome on Tuesday February 20, 2018 @09:47AM (#16420662)
What about the Identity monad? Does that "force sequencing"? What "sequencing relationship" does it create?

If you are convinced that the Identity monad does "force sequencing" then you are also convinced that lazy evaluation "forces sequencing" (because the Identity monad is just lazy evaluation). That would be a fairly controversion conviction. If you are not convinced that the Identity monad "forces sequencing" then can you explain in more detail the meaning of your claim "What a Monad does is to force sequencing by creating a data dependency.".

Re:Are Monads a Waste of Time? by tree_of_item on Tuesday February 20, 2018 @12:05PM (#16421848)
The identity monad's sequencing is just basic cause and effect: you need to have produced an `a` in order to get a `b`.

The sequencing is very obvious from the signature of `>>=`. You don't need to know anything about any instances to see that it's there.

Re:Are Monads a Waste of Time? by tome on Tuesday February 20, 2018 @01:03PM (#16422381)
> The identity monad's sequencing is just basic cause and effect: you need to have produced an `a` in order to get a `b`.

You most certainly do not! See https://news.ycombinator.com/item?id=16420742

Re:Are Monads a Waste of Time? by tree_of_item on Tuesday February 20, 2018 @01:21PM (#16422544)
It's in the signature. `b` has a causal dependency on `a` because `a` is on the left hand side of the arrow and `b` is on the right hand side of the arrow. That's it. Functional programming 101. There's no way around this.

The operational semantics and details of thunks are not relevant here. Tricks with `undefined` are not relevant here. This is just the meaning of the arrow type.

Re:Are Monads a Waste of Time? by pdpi on Tuesday February 20, 2018 @01:56PM (#16422912)
If that were true, why do you need a monad for sequencing? Why doesn’t function composition suffice, or something of the form a -> (a -> b) -> b?
Re:Are Monads a Waste of Time? by tree_of_item on Tuesday February 20, 2018 @02:57PM (#16423596)
Because the values have extra "stuff" surrounding them. That's why it's `m a` and not just `a`: the `m` holds the invisible context that enriches the `a`.

Although your example is exactly what's happening in the identity monad, because there is no extra stuff.

Re:Are Monads a Waste of Time? by gowld on Wednesday February 21, 2018 @02:00AM (#16427471)
Monads have been called "executable semicolons", because you can define a function to be executed each time the program passes from one statement to the next.
Re:Are Monads a Waste of Time? by jw- on Wednesday February 21, 2018 @09:55AM (#16429838)
How is sequencing described in the type of join?
Re:Are Monads a Waste of Time? by gowld on Wednesday February 21, 2018 @01:58AM (#16427464)
Tardis and the ReverseState monad are more examples of people being funny and clever by creating misleading names and mental-models instead of making libraries easy to understand.

There's no "time loop" in a cyclical data structure. There's just a data loop. Moving backward through a circular buffer, or doing arithmetic mod N, isn't "time travel"

Re:Are Monads a Waste of Time? by tathougies on Tuesday February 20, 2018 @05:35PM (#16424898)
But TardisT is sequenced in the monadic value. It is not sequenced in its inner backwards-traveling state, but that is not part of the monadic structure.

Have you used TardisT? In order to use the backwards traveling state, you need to bind the state syntactically before you use it, just as you have to do with the forwards traveling state.

For example, a typical setup for TardisT is fixing up jump offsets for an assembler. To write this, you do something like

    assembler (Label l) = do
       fixup <- getFuture
       (curOps, offset) <- getPast
       modifyBackwards (M.insert l offset)

       let ops = curOps ++ [ Jump (M.lookup l fixup) ]
       sendFuture (ops, offset + 1)
    assembler ... = ...
Note that both the forwards and backwards traveling state needed to be bound before they were used. There is an inherent 'forwards-traveling' sequencing due to the monadic structure.

If tardist were not monadically sequenced, you ought to be able to do

    assembler (Label l) = do
       (curOps, offset) <- getPast

       let ops = curOps ++ [ Jump (M.lookup l fixup) ]
       sendFuture (ops, offset + 1)

       fixup <- getFuture
       modifyBackwards (M.insert l offset)
In this sense, the forwards traveling state is privileged (and indeed if you write anything sufficiently complicated, you'll note that you'll need to add a lot of lazy pattern matches on the backwards traveling state, but not the forwards traveling one, again indicating a notion of sequencing, despite what it may seem).
Re:Are Monads a Waste of Time? by tome on Wednesday February 21, 2018 @02:40AM (#16427656)
Good explanation of Tardis, but would you really describe that as "forc[ing] sequencing by creating a data dependency"?
Re:Are Monads a Waste of Time? by tathougies on Wednesday February 21, 2018 @10:38AM (#16430181)
I would get rid of the forcing part, but I think my example shows it does cause a sequential dependency ?