I want a shorter way to write this block of code as this is going to be used in multiple places in a project I am working on. Is there a library I can use which would have a function for my specific need?
case mbData1, mbData2 of
(Just data1, Just data2) -> Just $ mergeData data1 data2
(Nothing, Just data2) -> Just data2
(Just data1, Nothing) -> Just data1
(Nothing, Nothing) -> Nothing
First, note that your expression only makes sense if mergeData x y has the same type as x and y each have, i.e. if its type is
mergeData :: X -> X -> X
for some concrete type X.
Given that, we can rely on Maybe's Applicative and Alternative instances:
mergeTwoMaybeDatas :: Maybe X -> Maybe X -> Maybe X
mergeTwoMaybeDatas a b = liftA2 mergeData a b <|> a <|> b
If you want to reuse this pattern many times but for different functions, and you think this is not clear, you could define a function parameterizing over mergeData.
But wait, maybe we can do something even simpler! If your mergeData function is associative (i.e., mergeData x (mergeData y z) = mergeData (mergeData x y) z), then your X type is a Semigroup, with mergeData as its combine operation. In that case, consider defining the Semigroup instance. Then you could use the tools designed for Semigroups to handle this even more simply.
data X = ...
instance Semigroup X where
(<>) = mergeData
mergeTwoMaybeDatas :: Maybe X -> Maybe X -> Maybe X
mergeTwoMaybeDatas = (<>)
Amazing: if you give X its Semigroup instance, you don't even have to implement mergeTwoMaybeDatas at all - it's just how (<>) already behaves for a Semigroup lifted into Maybe.
I encourage giving your types instances of all the typeclasses they can reasonably support: you will find many generic tools like this then work on them "for free". Having a Semigroup instance will likely help out for some of your other uses of this X type as well.
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