当< *>中的函数为Nothing时,为什么Maybe的Nant的Applicative实例无效

时间:2011-12-25 03:36:23

标签: haskell functor applicative

我是haskell的初学者,正在阅读“了解你是一本哈克尔书”。我一直试图消化仿函数和应用函子一段时间。

在applicative functors主题中,Maybe的实例实现为

instance Applicative Maybe where
  pure = Just
  Nothing <*> _ = Nothing
  (Just f) <*> something = fmap f something

因此,据我了解,如果左侧仿函数(Nothing)为Nothing,则会得到<*>。对我来说,似乎更有意义

  Nothing <*> something = something

因此,这个应用程序的仿函数没有效果。什么是用例,如果有的话给出Nothing

说,我和我有一个Maybe String,我的价值我不知道。我必须将此Maybe提供给第三方函数,但希望其结果首先经过几个Maybe (a -> b)。如果其中一些函数是Nothing,我会希望它们以静默方式返回其输入,而不是发出Nothing,这是数据丢失。

那么,在上面的例子中返回Nothing背后的想法是什么?

4 个答案:

答案 0 :(得分:15)

那怎么办?这是类型签名:

(<*>) :: Applicative f => f (a -> b) -> f a -> f b

所以这里的第二个参数是Maybe a类型,而结果需要是Maybe b类型。您需要某种方式将a转换为b,只有在第一个参数不是Nothing时才能执行此操作。

这样的唯一方法是,如果您有一个或多个Maybe (a -> a)类型的值,并且想要应用任何非Nothing的值。但这对于(<*>)的一般定义来说太具体了。


编辑:由于它似乎是您真正关心的Maybe (a -> a)方案,因此以下是一些关于您可以对该类型的一组值执行的操作的示例:

保留所有功能并丢弃Nothing,然后应用它们:

applyJust :: [Maybe (a -> a)] -> a -> a
applyJust = foldr (.) id . catMaybes

catMaybes函数为您提供仅包含Just值的列表,然后foldr将它们组合在一起,从身份函数开始(如果没有适用的功能)。

或者,你可以采取功能,直到找到Nothing,然后拯救:

applyWhileJust :: [Maybe (a -> a)] -> a -> a
applyWhileJust (Just f:fs) = f . applyWhileJust fs
applyWhileJust (Nothing:_) = id

这使用与上面类似的想法,除了它找到Nothing时忽略列表的其余部分。如果你愿意,你也可以把它写成applyWhileJust = foldr (maybe (const id) (.)) id,但这有点难以理解......

答案 1 :(得分:8)

<*>视为普通*运算符。 a * 0 == 0,对吧? a是什么并不重要。所以使用相同的逻辑Just (const a) <*> Nothing == NothingApplicative法律规定数据类型必须表现得像这样。

这有用的原因是Maybe应该表示某事物的存在,而不是缺席。如果通过一系列函数传递Maybe值,如果一个函数失败,则表示发生失败,并且该过程需要中止。

你提出的行为是不切实际的,因为它有很多问题:

  1. 如果失败的函数要返回其输入,则它必须具有类型a -> a,因为返回的值和输入值必须具有相同的类型才能使它们可互换,具体取决于函数的结果
  2. 根据您的逻辑,如果您有Just (const 2) <*> Just 5会怎样?如何使这种情况下的行为与Nothing案例保持一致?
  3. 另见the Applicative laws

    编辑:修正了代码拼写错误,再次

答案 2 :(得分:3)

那么这个呢?

Just id <*> Just something

当您开始使用&lt; *&gt;时,会出现Nothing的用例。通过多个输入检测功能。

(-) <$> readInt "foo" <*> readInt "3"

假设你有一个函数readInt :: String -> Maybe Int,这将转变为:

(-) <$> Nothing <*> Just 3

<$>仅为fmap,而fmap f NothingNothing,因此会缩减为:

Nothing <*> Just 3

你现在能看到为什么这会产生什么?表达式的原始含义是减去两个数字,但由于我们在第一次输入后未能生成部分应用的函数,我们需要传播该失败而不是仅仅构成一个与减法无关的好函数。

答案 3 :(得分:1)

除了C. A. McCann的优秀答案之外,我想指出这可能是一个“免费定理”的案例,见http://ttic.uchicago.edu/~dreyer/course/papers/wadler.pdf。本文的要点是,对于某些多态函数,对于给定的类型签名,只有一种可能的实现,例如: fst :: (a,b) -> a 没有其他选择而不是返回该对的第一个元素(或未定义),这可以证明。这个属性看似违反直觉,但根植于函数对其多态参数的非常有限的信息(特别是它不能凭空创建一个)。