Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Composing Monadic Functions with `<=<`

Tags:

haskell

I'm trying to understand the <=< function:

ghci> :t (<=<)
(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c

As I understand it, I give it 2 functions and an a, and then I'll get an m c.

So, why doesn't this example compile?

import Control.Monad

f :: a -> Maybe a
f = \x -> Just x

g :: a -> [a]
g = \x -> [x]

foo :: Monad m => a -> m c
foo x = f <=< g x

For foo 3, I would expect Just 3 as a result.

But I get this error:

File.hs:10:15:
    Couldn't match expected type `a0 -> Maybe c0'
                with actual type `[a]'
    In the return type of a call of `g'
    Probable cause: `g' is applied to too many arguments
    In the second argument of `(<=<)', namely `g x'
    In the expression: f <=< g x Failed, modules loaded: none.
like image 568
Kevin Meredith Avatar asked Dec 04 '25 13:12

Kevin Meredith


1 Answers

There are two errors here.

First, (<=<) only composes monadic functions if they share the same monad. In other words, you can use it to compose two Maybe functions:

(<=<) :: (b -> Maybe c) -> (a -> Maybe b) -> (a -> Maybe c)

... or two list functions:

(<=<) :: (b -> [c]) -> (a -> [b]) -> (a -> [c])

... but you cannot compose a list function and maybe function this way. The reason for this is that when you have a type signature like this:

(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> (a -> m c)

... the compiler will ensure that all the ms must match.

The second error is that you forgot to parenthesize your composition. What you probably intended was this:

(f <=< g) x

... if you omit the parentheses the compiler interprets it like this:

f <=< (g x)

An easy way to fix your function is just to define a helper function that converts Maybes to lists:

maybeToList :: Maybe a -> [a]
maybeToList  Nothing = []
maybeToList (Just a) = [a]

This function actually has the following two nice properties:

maybeToList . return = return

maybeToList . (f <=< g) = (maybeToList . f) <=< (maybeToList . g)

... which are functor laws if you treat (maybeToList .) as analogous to fmap and treat (<=<) as analogous to (.) and return as analogous to id.

Then the solution becomes:

(maybeToList . f <=< g) x
like image 155
Gabriella Gonzalez Avatar answered Dec 07 '25 16:12

Gabriella Gonzalez



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!