14

我是haskell的初学者,正在阅读Learn you a haskell book。一段时间以来,我一直在尝试消化函子和应用函子。

在应用函子主题中,实例实现Maybe

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

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

  Nothing <*> something = something

所以这个应用函子没有效果。有什么用例,如果有的话Nothing

说,我有一个Maybe String我不知道的价值。我必须把它Maybe交给第三方功能,但希望它的结果先通过几个Maybe (a -> b)。如果其中一些功能是Nothing我希望他们默默地返回他们的输入,而不是给出 a Nothing,这是数据丢失。

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

4

4 回答 4

15

那将如何运作?这是类型签名:

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

所以这里的第二个参数是 type Maybe a,而结果需要是 type Maybe b。您需要某种方式a变成b,只有当第一个参数不是 时,您才能这样做Nothing

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


编辑:因为这似乎是Maybe (a -> a)你真正关心的场景,这里有几个例子说明你可以用一堆这种类型的值做什么:

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

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

catMaybes函数为您提供一个仅包含Just值的列表,然后将foldr它们组合在一起,从标识函数开始(如果没有要应用的函数,您将获得该函数)。

或者,您可以使用函数直到找到 a Nothing,然后退出:

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

这使用了与上面类似的想法,只是当它找到Nothing它时会忽略列表的其余部分。如果你喜欢,你也可以写成这样,applyWhileJust = foldr (maybe (const id) (.)) id但读起来有点难……

于 2011-12-25T03:45:01.453 回答
8

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

这之所以有用,是因为Maybe它应该代表某物的存在,而不是某物的缺失。如果Maybe通过一系列函数传递一个值,如果一个函数失败,则意味着发生了失败,并且需要中止该过程。

您提出的行为是不切实际的,因为它存在许多问题:

  1. 如果失败的函数要返回其输入,则它必须具有 type a -> a,因为返回的值和输入值必须具有相同的类型才能根据函数的结果互换
  2. 根据你的逻辑,如果你有会发生什么Just (const 2) <*> Just 5?如何使本案中的行为与本案一致Nothing

法律Applicative

编辑:修复代码错别字,再一次

于 2011-12-25T03:49:09.647 回答
3

那么这个呢?

Just id <*> Just something

当您开始使用 <*> 来检测具有多个输入的函数时,Nothing 的用例就出现了。

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

假设你有一个 function readInt :: String -> Maybe Int,这将变成:

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

<$>fmap,并且fmap f NothingNothing,所以它简化为:

Nothing <*> Just 3

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

于 2011-12-25T11:39:00.903 回答
1

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

于 2011-12-25T12:57:51.743 回答