The M-word thing clicks today.
I started to learn Haskell two days ago when I started to rewrite this blog’s publisher automation. I find handling failure cases in IO is often challenging. When facing IO (Either a b), I often find myself don’t know how to do two things:
- Fetch the value wrapped by IO. For example, how to get the String from IO (Either String a)? The difficult part is that the inner value of IO is not accessible via pattern match.
- Wrap a value back to IO. For example, I have a Right “output”, how to convert it back to IO (Either a String)?
Then I come across Haskell for OCaml Programmers. The section Rolling your own recipe system is extremely useful. The "recipe system" mentioned in the article is extremely similar to Racket macro. The difference is that Haskell can find a “recipe” according to identifiers and context (i.e. types), whereas Racket can find a “recipe” according to identifiers and syntax patterns.
Take this example: IO and Either are just contexts, so they both know the recipe ">>=" because they implement the same type class. When >>= applies to variable a, Haskell decides which >>= to use (or which “recipe” to use) according to a‘s type.
All of a sudden, the M-word clicks. M-word provides context for computation, so don’t try to unwrap IO, just carry it on:
- It depends on two things to fetch the inner value wrapped by a context: if the constructor is accessible (e.g. Either, Maybe), pattern match can get the inner value. If the constructor is not accessible (e.g. IO), you have to carry the context along with the computation.
- To wrap some value into context (or lift the value), we can use pure. Every M-word instance defines pure.