
Three Useful Monads - timf
http://adit.io/posts/2013-06-10-three-useful-monads.html
======
lelandbatey
I'm really not feeling the music with these, if you know what I mean, which is
a shame since it seems as though great lengths have been gone to to make it
understandable.

Are there other works you can recommend to learn more from?

~~~
jamesaguilar
Agreed. The writer example was really telling. The whole syntax around using
the function changes when you bring the monad into it. Even the placement of
the function calls and the data.

~~~
wvs
"half 8 >>= half" might look a lot different from "half . half $ 8", but
they're actually identical in underlying structure! The monad version is just
using the wrong operator for visual comparison.

(.) composes two functions[1] but (>>=) composes a monad _value_ with a monad
function[2]. It'd be nice if we had an operator to compose two monad functions
instead.

We can define that operator in terms of (>>=): "g <=< f = \x -> f x >>= g".
You can check that the types work out[3]. Notice the great similarity to (.).
(It's because they're both categorical composition operators of functions.)

Now we can write "half <=< half $ 8" and everything's dandy.

    
    
      [1]: (.) :: (b -> c) -> (a -> b) -> (a -> c)
      [2]: (>>=) :: m a -> (a -> m b) -> m b
      [3]: (<=<) :: (b -> m c) -> (a -> m b) -> (a -> m c)

~~~
jamesaguilar
This is impressive, but it does not make me want to try Haskell more.

~~~
wvs
Ahaha, I agree. Abstract monad derivations are quite a foreboding
introduction.

------
tome

        half 8 >>= half
    

_It’s not quite half . half $ 8, but it’ll do_

but

    
    
        half <=< half $ 8
    

is!

~~~
prof_hobart
Well, it clearly isn't. It's an improvement, but "<=<" is still quite
different from ".". I can see it from here.

I'm sure there's an entirely justifiable reason why the two syntaxes have to
be different, but that doesn't stop it being a bit of a pain when it comes to
trying to learn the language - I've developed a bunch of side effect-free
code, and I want to stick a bit of logging in the middle of one bit to help me
see exactly what's going on, and suddenly I seem to need to rewrite half my
code to use a very similar, but subtly different syntax.

~~~
acomar
(<=<) is a generalization of (.), and it's one of a number of historical
issues that many Haskellers would like to see resolved, but everyone is afraid
to try because it would basically break every single available library (many
of which are no longer actively maintained). This is basically a library
issue, not a syntax issue. A similar issue is that the Monad typeclass doesn't
require a Functor instance, even though it's mathematically necessary. There's
a long standing argument over how the Prelude (standard library) should be
updated/modified, but there's a lot of bikeshedding going on.

~~~
tome
I don't think this is correct.

My understanding is that it's not a library issue, and in terms of Haskell
types (<=<) is not a generalisation of (.) (although it is mathematically
speaking).

If you want a -> m b to be a Category instance so you can use (.) you need the
Kleisli newtype wrapper. If you want a -> b to work in any monad so you can
use (<=<) you need to compose with return to get Monad m => a -> m b.

Either way you have to explicitly specify the isomorphism explicitly and I
don't think there's any getting around that.

------
dustingetz
so these are actually useful; below i link a fleshed out logger monad in a
scala webapp. I wrote it because at work (enterprise webapps) we want to be
able to send the logs created over the duration of a request down to the
client for diagnostics. Singleton loggers (mutable globals) interleave the
logs in a threaded context, and worse in async or high availability contexts,
and are basically a giant pain in the ass to extract useful data from.

the actual monadic types are:

    
    
        type MyLogger[+A] = WriterT[scalaz.Id.Id, List[String], A]
        type IOLogger[V] = EitherT[MyLogger, Throwable, V]
    

which represents either an exception or a value, alongside the logs that led
up to it.

[https://github.com/dustingetz/monadic-logging-
play/blob/mast...](https://github.com/dustingetz/monadic-logging-
play/blob/master/app/controllers/Root.scala)

Forgive me if this code is ugly, this is my first foray into scalaz. The repo
contains a complete minimum play app and will run. Also we're hiring in
philadelphia.

~~~
egonschiele
Glad you found the post useful!

------
daGrevis
This makes me want to learn Haskell once again and maybe, if I'm super lucky,
understand something! :)

------
gohrt
Until monad transformers are easy to use, monads are a one-way street to a
dead-end. Monads are so general that being confined to one per function is a
total blocker. Yet monad-transformers require far to much
mental/organizational overhead.

