在尝试找到可以逐步执行/允许线程化的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 = return
和(<*>) = ap
的应用函子。
对我来说,应用函子在概念上比monad更难。为了更好地理解applicative functor,我喜欢使用applicative instance而不诉诸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
的基本术语定义<*>
?
答案 0 :(得分: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
的标志:计算的结构是固定的,因此值取决于值,但动作不是。