I'm reminded of the Alternative
type class in Haskell's Control.Applicative
:
class Applicative f => Alternative f where
empty :: f a
(<|>) :: f a -> f a -> f a
A general version of your function for any instance of Alternative
might look like this:
liftOrAlternative :: (Alternative f) => (a -> a -> a) -> f a -> f a -> f a
liftOrAlternative f a b = f <$> a <*> b <|> a <|> b
ghci> liftOrAlternative (+) (Just 1) Nothing
Just 1
ghci> liftOrAlternative (+) (Just 1) (Just 2)
Just 3
ghci> liftOrAlternative (+) Nothing Nothing
Nothing
For Scala, I think the closest analogy to Alternative
would be the ApplicativePlus
type class from Scalaz.
def liftOrAlternative[A, F[_]: ApplicativePlus](f: (A, A) => A)(a: F[A], b: F[A]): F[A] =
f.lift[F].apply(a, b) <+> a <+> b
I admit that liftOrAlternative
is not a great name. After reading Twan van Laarhoven's answer, I think his suggestion of unionWith
is much better at expressing what the function actually does.