14

在尝试找到可以逐步执行/允许线程的haskell monad时,我发现了免费的monad

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

及其 monad 实例

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

及其函子实例

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

我知道每个 monad 都是一个带有pure = returnand的应用函子(<*>) = ap。对我来说,应用函子在概念上比单子更难。为了更好地理解应用函子,我喜欢使用应用实例而不使用ap.

第一行<*>很简单:

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

如何用和定义Roll f <*> x基本术语?fmap<*>

4

1 回答 1

19

这会吗?

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

计划是只对产生函数的树的叶子起作用,所以对于Return,我们通过将函数应用于由参数动作产生的所有参数值来行动。对于Roll,我们只是对所有子动作做我们打算对整体动作做的事情。

至关重要的是,我们在到达时所做的事情在Return我们开始之前就已经确定了。我们不会根据我们在树中的位置来改变我们的计划。这就是存在的标志Applicative:计算的结构是固定的,因此值依赖于值,但动作不依赖于值。

于 2014-03-02T00:07:39.120 回答