30 comments

[ 2.7 ms ] story [ 58.2 ms ] thread
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?

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.
"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)
This is impressive, but it does not make me want to try Haskell more.
Ahaha, I agree. Abstract monad derivations are quite a foreboding introduction.
Absolutely right! (And you preempted my comment at the top level).

I think one reason for "monad hell" is unawareness about this kind of composable style.

(comment deleted)
If you already know about high order functions and a bit of haskell notation, I suggest chapters 11 and 12 from "Learn You a Haskell for Great Good!" [1]. I think that following the explanation from Functors -> Applicative Functors -> Monoids -> Monads makes it easier to understand where monads come from and what problem they are trying to solve.

[1] http://learnyouahaskell.com/chapters

There are different kinds of people, some might learn by going the theoretical path you described (functors -> monoids -> monads). I am not one of these people. I learn theory by doing thing in practice.

I recommend starting out with IO and "learning monads" as you go. Too many people think they must "understand" monads first, but this might not be the right way to go depending on the person.

"Guess the number" and other examples from Imperative programming 101 make great exercises.

(comment deleted)
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...

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.

    half 8 >>= half
It’s not quite half . half $ 8, but it’ll do

but

    half <=< half $ 8
is!
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.

Granted, it's not exactly the same.

> I seem to need to rewrite half my code to use a very similar, but subtly different syntax.

Half is a massive over exaggeration if you've written it in the right way, i.e. the in the composable manner, preferring (.) and (<=<) over function application and (>>=). However, this I don't know how widely appreciated this style is. It's certainly not taught first in functional programming, unfortunately.

I certainly don't think it's the style I've picked up from any of the books/tutorials I've seen.

But even changing several levels of call from "." to "<=<" (and presumably back again when I've finished) because I've added a temporary logging call somewhere in the stack, still seems rather a pain.

I am not an expert by any stretches of the imagination, but I have some experience of Haskell at least. Currently writing a web app with Yesod (go check it out!). Outside of the trivial pure functions, pretty much all real work is done inside or one monad or another. At which point there is no change in syntax or level at all.

If you just want a temporary log consider using Haskell's debug features: http://www.haskell.org/ghc/docs/latest/html/libraries/base/D...

"For example, this returns the value of f x but first outputs the message.

trace ("calling f with x = " ++ show x) (f x)"

A good analogy is moving from procedural to object oriented code. It seems like a massive transition to organise code into separate objects which are instantiated rather than just using function pointers or gotos where you need to. But objects allow you to talk about frameworks and different architectures, separation of responsibilities and in general manipulate your code at a much higher level. Its worth pushing through to understand objects even if initially they are harder than naive procedural code. Similarly its worth taking the investment to understand monads rather than try to avoid them. In the longer run, they provide a higher level structure to the code.

What about:

    import Prelude hiding ((.))
    import Control.Category
    import Control.Arrow

    half' = Kleisli half

    ...

    runKleisli (half' . half') 8
Interesting. Does point to another reason why I've struggled with Haskell so far though - not having done university-level maths, I regularly hit terms (such as Kleisli categories) that mean absolutely nothing to me, and looking it up on Wikipedia makes my brain bleed.

I appreciate this is my problem rather than the language's, but I've worked in a huge array of different languages in the past 30 years and it's only ever functional ones where I hit the "what the hell does this even mean?" wall whilst trying to learn them...

Trying to understand monads and the Kleisli newtype by looking at the Wikipedia pages on monads and Kleisli categories is probably going to do more harm than good.

Trying to understand what a monad "is" is probably not worthwhile. It's actually quite easy to work out how to use them just by playing around with them.

Yeah, I don't think I've actually used Kleisli in production code.

Learning what a monad "is" is very worthwhile, but it's not where you start, because it's only tangentially related to how a monad is used.

you can also rewrite `half . half $ 8` as `half <=< half $ 8` in the identity monad. So if you aren't sure what monad you need, you can write the code against the identity monad and then change the monad later when you need to add logging.

An example where this shines is writing interpreters. You can write a "calculator" interpreter in identity monad, then add an environment (functions and lexical scope), then add errors, then make the environment mutable, then add continuations and try/catch. The core eval loop does not change as you implement new keywords like 'def' or 'throw'. In an imperative interpreter, each feature is coupled with the interpreter core.

I've done this in python but writing pure code in python is so crappy that it's not even worth sharing. Here is a short blog post though with code samples:

http://www.dustingetz.com/2012/10/02/reader-writer-state-mon...

(<=<) 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.
As someone learning the language, I'm not sure I care whether it's a syntax issue or a library issue. What I see is a language issue, and one that gets in the way of making learning it straightforward.
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.

This makes me want to learn Haskell once again and maybe, if I'm super lucky, understand something! :)
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.