addRecip :: Double -> Double -> Maybe Double
addRecip x y = fmap (+) (recipMay x) <*> recipMay y
where
recipMay a | a == 0 = Nothing
| otherwise = Just (1 / a)
我对<*>
进行了一些解释。
<*>
接受一个函子,该函子包含一个函数,该函数接受一个a
并返回一个b
,一个函子包含一个a,然后返回一个函子,该函子包含{{1} } a
。因此,b
可以从函子中提取函数并将其应用于函子内部的参数,最后将结果返回到函子
这是一个示例:
<*>
但就我而言,这似乎有些不同。 fs <*> xs = [f x | f <- fs, x <- xs]
中的元素不是函数。
答案 0 :(得分:3)
<*>将适用的值应用于另一个。它是常规函数应用程序的更丰富的对应。适用的值以某种方式修饰,例如,可以选择是否包含您认为的任何值(对于Maybe,这取决于您的情况),或者可以有很多值(对于List)。
因此,将一种应用价值应用到另一种应用上会有一些特殊的行为。对于列表,<*> b将a的每个成员应用于b的每个成员,从而形成所有组合的巨大列表,而对于Maybe(这是您的情况),如果a和*,a <*> b给出Just(a'b') b是(Just a')和(Just b'),如果a和b之一或两者都不为Nothing,则不提供任何信息-概括来说,也许是函数应用程序的可选值,如果不包含任何值,则结果不存在。
<*>的实现有一些规则,这意味着您始终可以将其视为[将“包含的函数”应用于“包含的值”],并且只要您在包含的域中进行所有工作即可(使用<$>,<*>,pure,>> =,<|>等),则可以将其认为与常规函数应用程序相同,但是当您“提取”值时,您会看到更加丰富。
答案 1 :(得分:3)
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
来自Applicative
类型类。 Applicative
是(引用文档)“ 带有应用程序的函子。”。您可以将Functor
视为一个集合(尽管有些其他类型不是像函子一样的集合,例如函数)。
如果我们将函子视为一个集合,则(<*>)
运算符将采用其中的两个集合。前一个集合存储类型为a -> b
的函数,后一个集合为b
的集合。然后,通过将第二个集合中的每个元素应用于第一个集合中的每个函数,得到b
s的集合(相同类型的集合)。
对于列表,它看起来像:
(<*>) :: [a -> b] -> [a] -> [b]
(<*>) fs xs = [fi xj | fi <- fs, xj <- xs]
Maybe
也是某种集合:它包含 no 元素(在Nothing
情况下)或 one 元素(在Just x
个元素,其中x
个元素)。因此,您可以将Maybe
视为具有“ 多样性” 0.1..1。
如果两个操作数之一是Nothing
(或两者都是),那么结果也是Nothing
,因为如果没有函数或元素,则不存在“结果”。仅在两个操作数均为Just
(因此Just f
和Just x
)的情况下,我们才能执行函数应用程序(因此Just (f x)
):
(<*>) :: Maybe (a -> b) -> Maybe a -> Maybe b
(<*>) (Just f) (Just x) = Just (f x)
(<*>) _ _ = Nothing
在这种情况下,我们可以分析其用途:
addRecip :: Double -> Double -> Maybe Double
addRecip x y = (fmap (+) (recipMay x)) <*> recipMay y
where
recipMay a | a == 0 = Nothing
| otherwise = Just (1 / a)
因此,我们看到两个操作数:fmap (+) (RecipMay x)
和recipMay y
。如果x
和/或y
为0
,则操作数分别为Nothing
。因为在那种情况下,对应的recipMay
是Nothing
。
因此,我们可以这样写:
addRecip :: Double -> Double -> Maybe Double
addRecip x y | x == 0 = Nothing
| y == 0 = Nothing
| otherwise = Just ((1/x) + (1/y))
但是在上面我们因此重复了== 0
和1/
逻辑两次。
答案 2 :(得分:2)
此处的函子为Maybe
。如果任一自变量为<*>
(即,它除以零),则Nothing
将返回Nothing
Nothing <*> _ = Nothing
_ <*> Nothing = Nothing
在其余情况下,它仅应用包装函数:
Just f <*> Just x = Just (f x)
还请注意
fmap (+) (recipMay x) <*> recipMay y
是一个有点不寻常的符号。通常写为
(+) <$> recipMay x <*> recipMay y
这是完全等效的,因为fmap
被写为中缀<$>
,但更具可读性。
在这里,fmap (+) (recipMay x)
(或(+) <$> recipMay x
)表示
if x == 0
then Nothing
else Just (\a -> 1/x + a)