我对函数式编程比较陌生(来自JavaScript),很难区分这两个概念,这也影响了我对于函子和单子的理解。
函子:
class Functor f where
fmap :: (a -> b) -> f a -> f b
单子(简化版):
class Monad m where
(>>=) :: m a -> (a -> m b) -> m b
fmap
接受一个函数和一个functor,并返回一个functor。>>=
接受一个函数和一个monad,并返回一个monad。
两者之间的区别在于函数参数:
fmap
-(a -> b)
>>=
-(a -> m b)
>>=
接受一个返回monad的函数参数。我知道这很重要,但我很难看到这个微小的差别是如何使monads比functors更强大的。有人能解释一下吗?
(>>=)
,(=<<)
更容易理解。对于f a -> f b
,函数g :: a -> b
不影响f
的“包装”--不会改变它。对于m a -> m b
,函数k :: a -> m b
本身创建了新的m
“包装”,因此它可以改变它。 - Will Ness>>=
可以做什么fmap
不能做的事情。在我的脑海中,它们是等效的,因为我没有看到一个例子,表明 fmap 是不足够的。 - m0menimap
函数从列表中筛选元素是不可能的,但是使用concatMap
函数可以实现。比如对于[1,2,3]
这个列表,使用map (\x->x+1) [1,2,3]
只能得到[2,3,4]
,而使用concatMap (\x-> [x,x+1|even x]) [1,2,3])
则可以得到[1,2,3,3,4]
。 - Will Nessfilter
操作只是map
的一种简化变体,但现在我意识到这根本不可能。 - m0menimap (\x -> [x|even x]) [1,2,3]
几乎实现“过滤”操作,但它会产生[[],[2],[]]
的结果,因此需要通过concat
进行另一层解释才能真正实现“过滤”。 - Will Ness