在 Haskell 中,是否有 <?> 运算符的抽象?



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

import Control.Applicative ((<|>))
x = mA <|> mB <?> c
(<?>) :: Maybe a -> a -> a
Just x  <?> _ = x
Nothing <?> y = y

其中mA :: Maybe a, mB :: Maybe a, c :: a, x :: a。基本上,代码说:选择第一个不是empty的选项,默认为c。您可以将其称为"反向Maybe monad",其中与<?>类似的是pure

同样地,我可以写成
Just x = mA <|> mB <|> pure c,

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

x = fromMaybe c (mA <|> mB)

因为fromMaybe === flip <?> .

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

显然AlternativeApplicative不够强大。

我错过了一个类型类吗?

我认为把事情留在(<?>) = flip fromMaybe是一个好主意。

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

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

如果ta为空或ta的第一个元素,则返回a。例子:

Just 0 <?> 10 == 0
Nothing <?> 0 == 0
[] <?> 10 == 10

实际上,我不喜欢您正在寻找的<?>操作符名称。如果你在Stackage或Hayoo上搜索Maybe a -> a -> a类型,你可以从errors包中找到?:操作符。

这个运算符叫做猫王-运算符。它在Groovy中以这种形式使用。Kotlin也有。这个运算符有助于处理命令式语言中的空值。但是,如果您想象Maybe a是某种可空类型,那么?:运算符对您来说也是有意义的。您可以观察到?:操作符背后有一些历史。

此外,<?>已经在一些软件包中使用,如megaparsec, attoparsec, optparse-generic等。你的项目很可能会用到其中的一个。因此,在使用您的elvis-operator版本时,您可能会遇到一些冲突。

我能想到的关于"空"的两个抽象概念是:

首先,MonadError: Maybe可以有instance MonadError () Maybe。但请参见https://github.com/ekmett/mtl/issues/27

第二,lens, _Empty,这是默认的比较(Eq)与mempty (Monoid)。然而MonoidAlternativeMaybe不一致。

最新更新