这是fmap 的中缀运算符版本。我喜欢把它想象成可以带来(大多数人说提升)一个纯函数到某个上下文中的东西,只要这个上下文是一个函子(和大多数数据- 具有类型参数的类型可以转换为函子)。
例如,假设你有一个函数
double :: Int -> Int
double x = 2 * x
但您正在处理列表[Nothing, Just 3, Just 1, Nothing, Just 0] 中的Maybe 值。您想将每个 Just-number 加倍,但您不知道如何操作。
您知道列表中有map,但如何处理Maybes?
你可以写
doubleList :: [Maybe Int] -> [Maybe Int]
doubleList = map doubleMaybe
where doubleMaybe (Just n) = Just (2*n)
doubleMaybe Nothing = Nothing
但这似乎很愚蠢,因为您已经拥有double
fmap 出现了 - fmap 提升 double 进入 Maybe: fmap double :: Maybe Int -> Maybe Int:
doubleList :: [Maybe Int] -> [Maybe Int]
doubleList = map (fmap double)
或者作为一个列表也是一个仿函数
doubleList :: [Maybe Int] -> [Maybe Int]
doubleList = fmap (fmap double)
或
doubleList :: [Maybe Int] -> [Maybe Int]
doubleList = (fmap . fmap) double
<$> 如果您有积分,就会派上用场 - 所以fmap double (Just 5) = double <$> Just 5。
您经常在 IO 计算中看到这一点(将某些函数提升到 IO),并且经常在 应用程序中看到。
为此让我们看看
add :: Int -> Int -> Int
add = (+)
如何将Maybe包裹的两个数字相加?
这里<$> 和<*> 真的很方便:
> add <$> Just 4 <*> Just 5
Just 9
> add <$> Just 4 <*> Nothing
Nothing
> add <$> Nothing <*> Just 5
Nothing
> add <$> Nothing <*> Nothing
Nothing
立即学习 IMO 应用程序并不那么重要。通常你可以使用do 符号来编写那些,而据我所见,初学者——尤其是来自更命令式语言的初学者——对此没有任何问题:
... do
a <- Just 4
b <- Just 5
pure $ add a b
但是函子真的无处不在——我想这只是习惯的问题。
如果您看到 SomeType a 并且想要 SomeType b 并且您知道如何使用 a -> b,或者如果您想要 SomeType a -> SomeType b 并且知道/拥有 a -> b - Functor, fmap 和 <$> 应该立即浮现在您的脑海中。