说实话,我通常只是发现不阅读这些简单函数中的代码,而是阅读类型然后自己编写函数更容易。把它想象成一个谜题。您正在尝试构建这个:
mapFree :: Functor f => (a -> b) -> Free f a -> Free f b
那么我们该怎么做呢?好吧,让我们Pure
先来看看构造函数:
mapFree f (Pure a) = ...
-- I like to write comments like these while using Haskell, then usually delete
-- them by the end:
--
-- f :: a -> b
-- a :: a
有了其中的两种类型的注释,并且知道 的类型Pure
,您应该立即看到解决方案:
mapFree f (Pure a) = Pure (f a)
现在是第二种情况:
mapFree f (Free fa) = ...
-- f :: a -> b
-- fa :: Functor f => f (Free f a)
好吧,既然f
是 a Functor
,我们实际上可以mapFree
用来应用于mapFree f
的内部组件f (Free f a)
。所以我们得到:
mapFree f (Free fa) = Free (fmap (mapFree f) fa)
现在,使用这个定义作为Functor f => Functor (Free f)
实例,我们得到:
instance Functor f => Functor (Free f) where
fmap f (Pure a) = Pure (f a)
fmap f (Free fa) = Free (fmap (fmap f) fa)
通过一些工作,您可以验证我们刚刚得出的定义与您正在困惑的定义相同。(正如其他人所提到的,(<$>)
(在 中定义Control.Applicative
)只是 . 的同义词fmap
。)您可能仍然不理解它,但您设法编写了它,对于这些抽象类型来说,这通常已经足够好了。
不过,就理解它而言,对我有帮助的是:将Free
monad 视为一种类似列表的结构,带有Pure
as[]
和Free
as (:)
。从类型的定义你应该看到:Pure
是基本情况,Free
是递归情况。实例正在做的fmap
是将映射的函数“推”到这个结构的底部,到它所在的位置Pure
。