免费monad的应用实例

Fra*_*nky 13 haskell applicative free-monad

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

data Free f a = Return a | Roll (f (Free f a))
Run Code Online (Sandbox Code Playgroud)

用它的monad实例

instance (Functor f) => Monad (Free f) where
  return = Return
  Return x    >>= f = f x
  Roll action >>= f = Roll $ fmap (>>= f) action
Run Code Online (Sandbox Code Playgroud)

和它的仿函数实例

instance (Functor f) => Functor (Free f) where
  fmap f (Return x) = Return (f x)
  fmap f (Roll   x) = Roll $ fmap (fmap f) x
Run Code Online (Sandbox Code Playgroud)

我知道每个monad都是一个带有pure = return和的应用函子(<*>) = ap.对我来说,应用函子在概念上比monad更难.为了更好地理解应用函子,我喜欢不依赖于应用实例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
Run Code Online (Sandbox Code Playgroud)

如何Roll f <*> xfmap和基本术语定义<*>

pig*_*ker 19

这会吗?

instance (Functor f) => Applicative (Free f) where
  pure = Return
  Return f  <*> as  = fmap f as
  Roll faf  <*> as  = Roll (fmap (<*> as) faf)
Run Code Online (Sandbox Code Playgroud)

计划是仅在产生函数的树的叶子上起作用,因此Return,我们通过将函数应用于参数动作产生的所有参数值来起作用.因为Roll,我们只是针对我们打算对整体行动做的所有子行动.

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