I have a function f
of type Integral => a -> a -> Maybe a
. This means that
f 1 2
is valid code, but natural compositions like
f (f 3 4) 5
f 6 (f 7 8)
f (f 9 10) (f 11 12)
are not valid.
There are ways to make it work. For example,
f 6 =<< f 7 8
is the nicest way I know for case 2. For case 3,
join $ f <$> f 9 10 <*> f 11 12
is the best I can think of, but the extra join
sticks out like a sore thumb. I don't have a good idea for case 1. Besides that, what bothers me is that the syntax in what I came up with is not "consistent" - I'm accomplishing essentially the same thing, but the syntax is very dissimilar.
Is there a standard/idiomatic construction which allows me to convert f
to work as Maybe a -> a -> Maybe a
, a -> Maybe a -> Maybe a
, and Maybe a -> Maybe a -> Maybe a
, with nice and consistent syntax?
Let's create a utility function for the first case:
lift :: (a -> b -> Maybe c) -> Maybe a -> b -> Maybe c
lift _ Nothing _ = Nothing
lift f (Just a) b = f a b
Case 1:
lift f (f 3 4) 5
Case 2:
f 6 =<< f 7 8
Case 3:
lift f (f 9 10) =<< f 11 12
Although it looks more consistent, yet in my humble opinion it still looks ugly. Perhaps somebody else could provide a better solution.
Edit: After thinking about my solution I realized that it can be generalized:
(<&>) :: (Applicative m, Monad m) => m (a -> m b) -> m a -> m b
f <&> a = join $ f <*> a
infixl 4 <&>
Case 1:
f <$> f 3 4 <&> pure 5
Case 2:
f <$> pure 6 <&> f 7 8
Case 3:
f <$> f 9 10 <&> f 11 12
This works for functions of an arbitrary arity:
f <$> a <&> b -- f :: a -> a -> Maybe a
f <$> a <*> b <&> c -- f :: a -> a -> a -> Maybe a
f <$> a <*> b <*> c <&> d -- f :: a -> a -> a -> a -> Maybe a
And so on....
Edit: I agree with @n.m. The best solution would be to change the type signature of your function to Maybe a -> Maybe a -> Maybe a
and use Just
wherever necessary.
Case 1:
f (f (Just 3) (Just 4)) (Just 5)
Case 2:
f (Just 6) (f (Just 7) (Just 8))
Case 3:
f (f (Just 9) (Just 10)) (f (Just 11) (Just 12))
The simplest solutions are always the best.
Edit: Actually, in retrospect my previous solution was much simpler.
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