在Haskell中研究函子,应用函子和monads,我在维基百科上找到了这个定义:
在函数式编程中,特别是 Haskell,一种应用 函子是一个类似于monad的结构(
return
,fmap
,join
( 没有join
,或者像一个有return
的函子。
我不明白:在我看来,提供return
(即 pure
(对函子的获得不足以获得应用函子,因为需要提供ap
(即 <*>
(也是如此,不能仅用fmap
和return
来定义。我错过了什么还是维基百科的定义不是绝对正确的?
编辑2017-02-08:我在这个答案中找到了关于这个问题的其他有用见解。
这篇文章不正确。假设我们有一个没有join
的 monad m
,或者一个带有 return
的函子。我们可以立即定义pure
:
pure :: Monad m => a -> m a
pure = return
但是,我们不能仅用fmap
和return
来定义(<*>)
。我们所拥有的只是 fmap
,所以如果我们尝试使用m (a -> b)
,我们最终会得到m (m a)
。此时我们需要join
或其等效(>>=)
:
(<*>) :: Monad m => m (a -> b) -> m a -> m b
f <*> x = join (fmap (flip fmap x) f)
-- or, easier to read:
-- f <*> x = do
-- f' <- f
-- x' <- x
-- return f' x'
应用函子就像一个函子,有return
和ap
,但没有join
。所以是的,你是完全正确的,维基百科错过了应用的操作(见原始论文(。
顺便说一下,如果你只添加 pure
,你会得到一个尖头函子。不过,类型百科比维基百科文章提供了更好的Applicative
概述。
你是对的,应用函子需要<*>
以及最小定义的pure
。 值得注意的是,我们可以从中得到fmap
,不过:
fmap f a = pure f <*> a
类似地,我们可以从monads中得到应用定义:
pure = return
f' <*> a' = do
f <- f'
a <- a'
return $ f a
您可以将应用函子视为多参数函数的泛化,或者将值与上下文水平组合:
liftA2 f a b = f <$> a <*> b
fmap :: (a -> b) -> (f a -> f b)
liftA2 :: (a -> b -> c) -> (f a -> f b -> f c)