Skip to content

Composition

Lanny Ripple edited this page May 6, 2017 · 7 revisions

So let's start why any of this advanced type stuff is of any use. Folks are raving about it. Folks maybe you think might have some clue. And looking at it seems like a lot of work to just turn a List[Option[A]] into an Option[List[A]]. (If you aren't programming the sorts of things where you need that then yes, it's of no use to you.)

The reason is composition. Functions compose. If I give you f: A => B and g: B => C then there is an operation called compose on those functions such that compose(f, g): A => C. And since compose gives me back a function I can keep composing. I can take a bunch of little functions that do little things and I can compose them so that at the end I have a little function that does lots of little things (hint: lots of little things are how you get big things).

That's great for functions. The next step up is (ignore Monoid for a moment) Functor. I'll cut to the chase and just tell you Functors compose. Recall from the future (because this is the first page and you haven't gotten there yet) that a Functor basically gives you map: (A => B) => (Functor[A] => Functor[B]). And I'm already sure you see where this is going. I'm about to tell you there's some operation on Functors such that compose(fab, fbc): Functor[AC] will end up giving me a map: (A => C) => (Functor[A] => Functor[C]). And hey -- that's a Functor too so I can keep composing.

And that's both the little reason (Who cares?) and the big reason (OMG! Life changing!!) that all this is important. Functions compose. Functors compose. Applicatives compose. Alas Monads don't compose.

Wait, what!? Ok. Yes, Monads don't compose. Luckily we can cheat a little and there are things called Monad Transformers that given a couple of Monads we can do things as if they compose. It's not a perfect world but it's not bad.

And now recall how I told you to forget about Monoid? A Monoid describes how to take two values of a type and append them together to get a single value of the type. If that sounds like compose that's because it is.

Composition Laws

The compiler can't easily check that composition will work cleanly for any given type. Thus the programmer should be conversant with the laws that have to hold. They are, basically

  1. Composition must be associative (i.e., Have a SemiGroup)
    a . (b . c) === (a . b) . c
  2. Composition's zero can be composed either first, or last. (Or both but that's just the zero again.)
    (0 . a) === (a . 0)

Again if these sound a lot like what you have to show for Monoid you are probably starting to see what ties all this stuff together.

Clone this wiki locally