Three Useful Monads
adit.io
adit.io
Are there other works you can recommend to learn more from?
(.) 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)I think one reason for "monad hell" is unawareness about this kind of composable style.
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.
http://www.chrisstucchio.com/blog/2013/write_some_fucking_co...
You could also check out this post by sigfpe, one of my favorite posts on monads: http://blog.sigfpe.com/2006/08/you-could-have-invented-monad...
half 8 >>= half
It’s not quite half . half $ 8, but it’ll dobut
half <=< half $ 8
is!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.
> 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.
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.
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.
import Prelude hiding ((.))
import Control.Category
import Control.Arrow
half' = Kleisli half
...
runKleisli (half' . half') 8I 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 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.
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.
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...
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.
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.