<*>在addRecip x y = fmap(+)(recipMay x)<*> recipMay y中做什么?

时间:2018-08-19 08:58:03

标签: haskell applicative

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] 中的元素不是函数。

3 个答案:

答案 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 fJust 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和/或y0,则操作数分别为Nothing。因为在那种情况下,对应的recipMayNothing

因此,我们可以这样写:

addRecip :: Double -> Double -> Maybe Double
addRecip x y | x == 0 = Nothing
             | y == 0 = Nothing
             | otherwise = Just ((1/x) + (1/y))

但是在上面我们因此重复了== 01/逻辑两次。

答案 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)