在Haskell中,符号<$>和<*>代表什么意思?

6

符号<$><*>代表什么意思?

此外,我了解到一些关于<$$>的信息。


2
谷歌并不是搜索符号的最佳引擎(虽然有Symbolhound,但我现在无法得到任何结果),特别是对于Haskell而言,因为它有两个出色的搜索引擎[http://hayoo.fh-wedel.de/?query=%3C%24%3E],可以立即指向定义。 - leftaroundabout
曾经听说过Hoogle吗?https://www.haskell.org/hoogle/?hoogle=%3C$%3E - AJF
@AJFarmar,是的,现在我知道这个服务了。 - Denis
2个回答

9

这些运算符在 Control.Applicative 中定义。 <$> 运算符只是 fmap 的中缀版本:

f <$> a = fmap f a

<*>Applicative 类定义的一部分:

class Functor f => Applicative f where
    pure :: a -> f a
    (<*>) :: f (a -> b) -> f a -> f b

你可以使用 Hoogle 更轻松地搜索 Haskell 函数和操作符。 Applicative 类型类位于 FunctorMonad 之间。
class Functor where ...

class Functor f => Applicative f where ...

class Applicative m => Monad m where ...

(请注意,这是仅在最近发布的GHC 7.10中强制执行的ApplicativeMonad之间的关系)

Applicative是遵循特定规则的结构。 它比functor更强大,但比monad更弱。 具体而言,functor只能将单参数函数应用于结构中的值,返回一个包含新值但不包含新形状的新结构。 典型的例子是fmap(+1)[1,2,3] == [2,3,4],输入列表的长度总是与输出列表相同。 在applicatives中,您可以跨多个结构应用多参数纯函数:

> (+) <$> [1, 2, 3] <*> [10, 20]
[11, 21, 12, 22, 13, 23]

输出列表的长度(即其“形状”)取决于输入列表的长度。 但需要注意的是,输出列表的长度不取决于列表内部的值。 这正是单子为该层次结构增加的强大功能:

> print $ do a <- [1, 2, 3]; b <- replicate a 10; return (a + b)
[11, 12, 12, 13, 13, 13]

在这里,我们将两个结构体组合在一起,其中一个结构体的“形状”取决于另一个结构体中的值。仅使用应用程序无法实现此操作,这也是为什么单子在Haskell中如此普遍的原因。然而,由于每个Monad都是一个Applicative,而每个Applicative都是一个Functor,因此在使用Monad时仍然可以访问所有这些工具。


在最后一个例子中,应该是 [1, 2, 3] 吗? - Sebastian Redl
@SebastianRedl,本来应该是1而不是a,感谢您指出。 - bheklilr
@Denis 没问题!我要说,理解应用函子花了我相当长的时间,它们是一种在函子和单子之间有些微妙差别的奇怪领域,这些差别并不是立即显而易见的。此时,我鼓励您通过流行的parsec或attoparsec库尝试更多地了解应用函子,这两个库都严重依赖于应用操作符。虽然了解如何使用它们很重要,但在许多情况下,完全可以不使用它们。大多数人会更喜欢<$>而不是fmap,所以预计会经常看到它。 - bheklilr
值得一提的是,(+) <$> [1,2,3]实际上是[(1+), (2+), (3+)] - mb14

4
< p > <$>是fmap的同义词,<$>是中缀运算符。它通常用于应用函子的上下文中。< /p >
import Control.Applicative ((<$>)

-- (<$>), fmap :: Functor f => (a -> b) -> f a -> f b

example1 :: (Int -> Int) -> Maybe Int -> Maybe Int
example1 f g = f <$> g  -- f `fmap` (Just x) = Just (f x)
                        -- f `fmap` Nothing  = Nothing

另一方面,<*> 在将函数应用于另一个 functor 上下文中的某个值时非常有用,例如:

example2:: Maybe (Int -> Int) -> Maybe Int -> Maybe Int
example2 f g = f <*> g -- (Just f) <*> (Just x) = Just ( f x)
                       -- Nothing  <*> (Just x ) = Nothing
                       -- (Just f) <*> Nothing   = Nothing
                       -- Nothing <*>  Nothing   = Nothing

它可以被视为一个操作符,应用函数的同时考虑函数所在的上下文。

这些操作符将值和函数提升到Functor的上下文中,其中执行操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接