Question

I'm going through some Haskell tutorials and trying to get familiar with the language. I've seen this example in a Monad/MonadPlus tutorial:

data Sheep = Sheep {name :: String, mother :: Maybe Sheep, father :: Maybe Sheep}
parent :: Sheep -> Maybe Sheep
parent s = mother s `mplus` father s

I was trying to rewrite it in point-free style (just as an exercise, not saying that the above is wrong or non-idiomatic), but I got stuck: obviously I can write a custom function

partialPlus :: (MonadPlus m) => (a -> m b) -> (a -> m b) -> a -> m b
partialPlus f1 f2 = \x -> f1 x `mplus` f2 x

and then use

parent = partialPlus mother father

but I seem to remember from the LYAH tutorial that there was a way to use functors or applicative functors to construct tree of computations that can be finally fed arguments to get the result out of the "functor-box". However I can't seem to find the example in the tutorial. How do I rewrite the above "cleverly"?

Was it helpful?

Solution

Using the Applicative instance for functions:

parent :: Sheep -> Maybe Sheep
parent = mplus <$> mother <*> father

OTHER TIPS

Very point-free

You could write it as

partialPlus :: MonadPlus m => (t -> m a) -> (t -> m a) -> t -> m a
partialPlus = liftM2 mplus

this works because of the monad instance for (->) t (which you can think of as meaning (t ->).

The types in more detail:

liftM2 :: Monad func_t => (a -> b -> c) -> func_t a -> func_t b -> func_t c

Giving it the highly prejudicial name func_t to suggest function from t to...

so then

liftM2 mplus :: (Monad func_t, MonadPlus m) => func_t (m a) -> func_t (m a) -> func_t (m a)

But why use Monad when you can have the nicer Applicative?

Or Why I stole hammar's nice answer:

Now, there's an applicative instance for (->) t and so we could just as well have written

partialPlus = liftA2 mplus

which works for exactly the same reason. But that's great news, because if you can use liftA2 or liftA3 etc, you can do it with the awesome <$> and <*> from Control.Applicative.

In general, if you have

this = do
  x <- mx
  y <- my
  z <- mz
  return (f x y z)

that's expressible as liftM3 f mx my mz, but more nicely as f <$> mx <*> my <*> mz, especially if mx and my etc are actually more complicated expression, as I find usually. <*> and <*> have low precedence (4) so you don't need brackets most of the time.

In this case we can have

partialPlus f1 f2 = mplus <$> f1 <*> f2

which is point-free. (...as long as you consider t -> m a as not a point!)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top