I just found myself writing this code:
import Control.Applicative ((<|>))
x = mA <|> mB <?> c
(<?>) :: Maybe a -> a -> a
Just x <?> _ = x
Nothing <?> y = y
Where mA :: Maybe a
, mB :: Maybe a
, c :: a
, and x :: a
. Basically, the code says: pick the first alternative that is not empty
and default to c
. You can call it "reverse Maybe monad" where the analogy to <?>
would be pure
.
Equivalently, I could have written
Just x = mA <|> mB <|> pure c,
but I feel uncomfortable with the irrefutable pattern. Or, of course,
x = fromMaybe c (mA <|> mB)
because fromMaybe === flip <?>
.
The <?>
operator is inspired from parsec. I always get suspicious when I find myself defining utility functions like that, but I couldn't find this defaulting behavior anywhere.
Apparently Alternative
and Applicative
are not powerful enough.
Did I miss a type-class?
I think it's a good idea to leave things at (<?>) = flip fromMaybe
.
If you'd like to generalize though, Foldable
seems to be the simplest class with a notion of emptiness:
(<?>) :: Foldable t => t a -> a -> a
ta <?> a = foldr const a ta
This returns a
if ta
is empty or else the first element of ta
. Examples:
Just 0 <?> 10 == 0
Nothing <?> 0 == 0
[] <?> 10 == 10
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With