也许合并运算符

时间:2017-11-18 22:56:57

标签: haskell null maybe null-coalescing-operator

我想知道如何定义一个运算符/如果Haskell中已经存在一个运算符,它允许选择不是Maybe的第一个Nothing类型,如果它们都是没什么,它返回一些默认值。基本上是这样的:

let x = a ?? b ?? c ?? 1

其中(??)是运算符,a, b, cMaybe类型。如果所有Just都是1,我希望此代码返回a, b, cNothing的第一个值。

我基本上希望复制与您在C#或其他语言中找到的空合并运算符相同的功能。

这个问题说明了如何做到这一点  F#(Null Coalescing Operator in F#?),而且非常hacky。有没有办法在Haskell中干净利落地完成它,如果没有,你能找到最接近它的是什么?

3 个答案:

答案 0 :(得分:12)

Haskeller一般会使用(<|>) :: Maybe a -> Maybe a -> Maybe a来做这类事情。假设a, b, c :: Maybe Int,您有x :: Maybe Int

let x = a <|> b <|> c <|> Just 1

当然,这并不是你要求的。如果你愿意,你可以定义它!

-- You expect `a ?? b ?? c ?? 1` to parse as `a ?? (b ?? (c ?? 1))`
infixr 3 ??

-- (Someone is going to point out that `(??) = flip fromMaybe`, so I am first)
(??) :: Maybe a -> a -> a
Just x ?? _ = x
Nothing ?? y = y

然后,您将获得您期望的行为。假设a, b, c :: Maybe Int,您有x :: Int

let x = a ?? b ?? c ?? 1

答案 1 :(得分:3)

你介意用不同的方式写吗?

safeHead [] d = d
safeHead (h:_) _ = h

然后

let x = safeHead (catMaybes [a, b, c]) 1

应该做你想做的事。

如果你想以这种方式做,那是可行的,但需要两个操作员。

a@(Just _) ?? _ = a
_ ?? b = b

(Just e) ?: _ = e
_ ?: d = d

定义了您需要的两个运算符,它们可以工作:

Prelude> let a = Nothing
Prelude> let b = Nothing
Prelude> let c = Just 3
Prelude> a ?? b ?? c ?: 10
3
Prelude> a ?? b ?? Nothing ?: 10
10

答案 2 :(得分:1)

仅仅为了某些练习目的,这个工作也可以用Monoid类类型First来表示,Maybe类型返回最左边的非Nothing值。

import Data.Monoid
import Data.Maybe (fromJust)

infixr 3 ??

(??) :: Maybe a -> a -> a
x ?? y = fromJust . getFirst $ First x <> First (Just y)

*Main> Nothing ?? Nothing ?? 1
1
*Main> Nothing ?? Just 3 ?? 1
3
*Main> Just 7 ?? Just 3 ?? 1
7