I’m curious of different ways of combining Maybes. There’s a small example of what I am able to achieve with a do (I reckon using the fact Maybe is a monad), however for this particular example I’m wondering if I can just use the semigroup. I tried something like
instance Semigroup (Maybe Int) where
(Just x) <> (Just y) = Just (x + y)
_ <> _ = Nothing
but this just throws a compile error. Parametrising over Num a
would be the next step. My thought was if it was possible to just combine like m1 <> m2
as writing extra functions feels unnecessary, though I don’t have a good grasp of things yet.
Example of what I’m trying to do:
m1 :: Maybe Int
m1 = Just 1
m2 :: Maybe Int
m2 = Just 11
m3 :: Maybe Int
m3 = Nothing
combine :: (Num a) => Maybe a -> Maybe a -> Maybe a
combine x y = do
a <- x
b <- y
return (a + b)
main :: IO ()
main = do
print $ combine m1 m2
print $ combine m1 m3
print $ combine m2 m3
Results:
Just 12
Nothing
Nothing
15
My thought was if it was possible to just combine like
m1 <> m2
.
It is possible. Likely the error you get is that you are defining an instance for something for which there is already a (more generic) instance. Indeed, it is defined as:
instance Semigroup a => Semigroup (Maybe a) where
Just x <> Just y = Just (x <> y)
Nothing <> x = x
x <> _ = x
So if the item the Maybe
is wrapping, is an instance of Semigroup
, you can combine these.
Now, Int
is not an instance of Semigroup
, but they defined types like Sum
[Hackage] and Product
[Hackage] to pick the Semigroup
you want, so we can work with:
Just (Sum 1) <> Just (Sum 2) -- Just (Sum 3)
we thus can then use getSum
to get the sum out of it:
getSum <$> (Just (Sum 1) <> Just (Sum 2)) -- Just 3
If one of the two is a Nothing
, the other parameter is returned. This thus means that Just (Sum 1) <> Nothing
is Just (Sum 1)
.
But probably here a more useful algebraic structure for this use case is the Applicative
[Hackage]. For a Maybe
, this will then combine two Just
s, so:
import Control.Applicative(liftA2)
liftA2 (+) (Just 1) (Just 2) -- Just 3
7