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