6

我刚刚发现自己正在编写这段代码:

import Control.Applicative ((<|>))

x = mA <|> mB <?> c

(<?>) :: Maybe a -> a -> a
Just x  <?> _ = x
Nothing <?> y = y

其中mA :: Maybe a, mB :: Maybe a,c :: ax :: a. 基本上,代码说:选择第一个不是empty并且默认为c. <?>您可以将其称为“reverse Maybe monad”,类似于pure.

等效地,我可以写

Just x = mA <|> mB <|> pure c,

但我对无可辩驳的模式感到不舒服。或者,当然,

x = fromMaybe c (mA <|> mB)

因为fromMaybe === flip <?>.

运算符的<?>灵感来自 parsec。当我发现自己定义了这样的实用函数时,我总是会产生怀疑,但我在任何地方都找不到这种默认行为。

显然AlternativeApplicative不够强大。

我错过了一个类型类吗?

4

3 回答 3

9

我认为把东西留在 . 是个好主意(<?>) = flip fromMaybe

但是,如果您想概括一下,Foldable似乎是具有空虚概念的最简单的类:

(<?>) :: Foldable t => t a -> a -> a
ta <?> a = foldr const a ta 

这将返回aifta为空,否则返回 的第一个元素ta。例子:

Just 0 <?> 10 == 0
Nothing <?> 0 == 0
[] <?> 10 == 10
于 2016-08-29T09:19:16.283 回答
4

实际上,我不喜欢<?>您要查找的操作员名称。如果您在StackageHayoo上搜索Maybe a -> a -> atype,您可以从package中找到operator 。?:errors

这个运算符就是所谓的elvis -operator。它以这种形式在 Groovy 中使用。Kotlin也有它。该运算符有助于处理命令式语言中的空值。但是,如果您认为这Maybe a是某种可以为空的类型,那么?:运算符对您也很有意义。您可以观察到运算符背后有一些历史的事实?:

此外,<?>已经在一些包中使用,如megaparsecattoparsecoptparse-generic等。您的项目可能会使用其中一种概率很高的项目。因此,使用您的elvis -operator 版本时,您可能会遇到一些冲突。

于 2016-08-29T11:45:01.517 回答
3

我能想到的唯一两个抽象的“空虚”是:

首先,MonadError:Maybe可能有instance MonadError () Maybe. 但是请参阅https://github.com/ekmett/mtl/issues/27

其次,lens _Empty默认情况下将 ( Eq) 与mempty(of Monoid) 进行比较。然而MonoidAlternative不同意Maybe

然而,我不记得有任何操作员直接在上述任何一个上工作。

于 2016-08-29T09:11:33.060 回答