我是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
背后的想法是什么?
答案 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 == Nothing
。 Applicative
法律规定数据类型必须表现得像这样。
这有用的原因是Maybe
应该表示某事物的存在,而不是缺席。如果通过一系列函数传递Maybe
值,如果一个函数失败,则表示发生失败,并且该过程需要中止。
你提出的行为是不切实际的,因为它有很多问题:
a -> a
,因为返回的值和输入值必须具有相同的类型才能使它们可互换,具体取决于函数的结果Just (const 2) <*> Just 5
会怎样?如何使这种情况下的行为与Nothing
案例保持一致?编辑:修正了代码拼写错误,再次
答案 2 :(得分:3)
那么这个呢?
Just id <*> Just something
当您开始使用&lt; *&gt;时,会出现Nothing的用例。通过多个输入检测功能。
(-) <$> readInt "foo" <*> readInt "3"
假设你有一个函数readInt :: String -> Maybe Int
,这将转变为:
(-) <$> Nothing <*> Just 3
<$>
仅为fmap
,而fmap f Nothing
为Nothing
,因此会缩减为:
Nothing <*> Just 3
你现在能看到为什么这会产生什么?表达式的原始含义是减去两个数字,但由于我们在第一次输入后未能生成部分应用的函数,我们需要传播该失败而不是仅仅构成一个与减法无关的好函数。
答案 3 :(得分:1)
除了C. A. McCann的优秀答案之外,我想指出这可能是一个“免费定理”的案例,见http://ttic.uchicago.edu/~dreyer/course/papers/wadler.pdf。本文的要点是,对于某些多态函数,对于给定的类型签名,只有一种可能的实现,例如: fst :: (a,b) -> a
没有其他选择而不是返回该对的第一个元素(或未定义),这可以证明。这个属性看似违反直觉,但根植于函数对其多态参数的非常有限的信息(特别是它不能凭空创建一个)。