Home > Enterprise >  Combine two Just values if present, else return first Just
Combine two Just values if present, else return first Just

Time:08-03

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

CodePudding user response:

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.

CodePudding user response:

You're looking for the salign function from the semialign package. Create a Semigroup instance for your type, with (<>) = mergeData (or inline its definition and just always call it this way), and then just call salign mbData1 mbData2.

  • Related