How to use higher-order constructs in a particular case

I want to write a function that takes two Maybe Int parameters and returns the minimum of them if they are both Just number, and 'the other' if either of them is Nothing. I'm not satisfied with my first attempt:

maybeMin :: Maybe Int -> Maybe Int -> Maybe Int
maybeMin Nothing arr = arr
maybeMin ell Nothing = ell
maybeMin ell@(Just l) arr@(Just r) = if l < r then ell else arr

As an optimisation I don't want to create a new value in the third case; i.e., I don't want to write

maybeMin ell@(Just l) arr@(Just r) = Just $ if l < r then l else r

The above code seems clunky and it seems to me that I ought to be able to exploit the fact that Maybe is an instance of Functor, Applicative or Monad. However, my best attempt to go higher-order doesn't do the same thing:

maybeMin ell arr = ell >>= (\l -> arr >>= (\r -> if l < r then ell else arr))

because it will return Nothing if either operand be Nothing.

Is there an elegant way to do what I want?

Upvotes: 2

Views: 61

Answers (1)

DDub
DDub

Reputation: 3924

You looked at Functor, Applicative, and Monad, but you may want to check out Alternative. As an example of its use, Just 3 <|> Nothing will yield Just 3 and not Nothing.

For your particular use, if you want a one-liner, you could try:

maybeMin l r = min l r <|> l <|> r

Just to break that down, we first calculate min l r, which uses the Ord instance of Maybe to give the minimum of l and r if both are Just values. If this works, then the computation stops there, but if either one isn't Just, then we check to see if l is a Just value. If it is, then that is the result, and if not, we end up returning r as the result.

Upvotes: 8

Related Questions