Applicative instance for free monad

While trying to find a haskell monad that can be executed stepwise / allows threading, I discovered the free monad

data Free f a = Return a | Roll (f (Free f a))

with its monad instance

instance (Functor f) => Monad (Free f) where
  return = Return
  Return x    >>= f = f x
  Roll action >>= f = Roll $ fmap (>>= f) action

and its functor instance

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

I know that every monad is an applicative functor with pure = return and (<*>) = ap . For me, applicative functors are conceptually harder than monads. For a better understanding of applicative functors, I like to have the applicative instance without resorting to ap .

The first line for <*> is easy:

instance (Applicative f) => Applicative (Free f) where
  pure = Return
  Return f <*> x = fmap f x -- follows immediately from pure f <*> x = f <$> x
--Roll   f <*> x = Roll $ (fmap ((fmap f) <*>)) x -- wrong, does not type-check

How to define Roll f <*> x in basic terms with fmap and <*> ?


Will this do?

instance (Functor f) => Applicative (Free f) where
  pure = Return
  Return f  <*> as  = fmap f as
  Roll faf  <*> as  = Roll (fmap (<*> as) faf)

The plan is to act only at the leaves of the tree which produces the function, so for Return , we act by applying the function to all the argument values produced by the argument action. For Roll , we just do to all the sub-actions what we intend to do to the overall action.

Crucially, what we do when we reach Return is already set before we start. We don't change our plans depending on where we are in the tree. That's the hallmark of being Applicative : the structure of the computation is fixed, so that values depend on values but actions don't.

链接地址: http://www.djcxy.com/p/47696.html

上一篇: 为什么在Haskell Monads中将“bind”写为>> =?

下一篇: 适用于免费monad的应用程序实例