Max Hallinan

How Does Free Make Any Functor a Monad?

Free gives us a Monad instance for any Functor. If map is defined for f a, then bind is defined for Free f a. And just like any Monad, we have an Applicative instance too. We get these instances for free, without implementing the operations by hand. But how?

Pure is easy. The Free type contains a Pure data constructor which lifts any a into Free f a.

data Free f a
  = Pure a
  | Free (f (Free f a))

instance Functor f => Applicative (Free f) where
  pure = Pure

instance Functor f => Monad (Free f) where
  return = pure

The trickier question is how Free gives us map, ap, and bind.

Again, the Pure case is straightforward. We can destructure Pure and apply our function to a just as we would for common Functors like Maybe and Either.

instance Functor f => Functor (Free f) where
  fmap k (Pure x) = Pure (k x)

instance Functor f => Applicative (Free f) where
  (<*>) (Pure k) (Pure x) = Pure $ k x

instance Functor f => Monad (Free f) where
  (>>=) (Pure x) k = k x

It’s the Free case that trips us up. How do we reach a when it’s encased in layers of Free and f? We can strip the first layer of Free with pattern matching. This exposes the layer f. And we can use map to lift our function over that layer. But we still haven’t reached a. We’re confronted by a second layer of Free.

instance Functor f => Functor (Free f) where
  fmap k (Free x) = Free $ fmap ? x

instance Functor f => Applicative (Free f) where
  (<*>) (Pure k) (Free x) = Free $ fmap ? x
  (<*>) (Free k) x = Free $ fmap ? k

instance Functor f => Monad (Free f) where
  (>>=) (Free x) k = Free $ fmap ? x

Free is a recursive type. So the definitions of map, ap, and bind must also be recursive. Instead of lifting the function k over the structure f, we lift a recursive call to map, ap, or bind.

instance Functor f => Functor (Free f) where
  fmap k (Free x) = Free $ fmap (fmap k) x

instance Functor f => Applicative (Free f) where
  (<*>) (Pure k) (Free x) = Free $ fmap (fmap k) x
  (<*>) (Free k) x = Free $ fmap (<*> x) k

instance Functor f => Monad (Free f) where
  (>>=) (Free x) k = Free $ fmap (>>= k) x

Pure is the base case of that recursion. We keep expanding the recursive chain of Free and f until we reach the Pure case. Then a is exposed and we transform a into b.

not' :: Functor f => Bool -> Free f Bool
not' x = return $ not x

>>= (Free (Just (Free (Just (Pure True))))) not'
Free $ fmap (>>= not') (Just (Free (Just (Pure True))))
Free $ Just $ (>>= not') (Free (Just (Pure True)))
Free $ Just $ Free $ fmap (>>= not') (Just (Pure True))
Free $ Just $ Free $ Just $ (>>= not') (Pure True)
Free $ Just $ Free $ Just $ not' True
Free $ Just $ Free $ Just $ Pure False

For Free to give us a Monad for any Functor, two things must be accomplished. First, we must expose a without knowing anything about f. That is why there is a layer of Free between f and a. Because we know how to destructure Free, we can access a without knowing how to destructure f. Second, we must preserve the behavior of f. That is why f must have an instance of Functor. Using map to navigate f preserves the behavior of f.