There I was, writing a function that takes a value as input, calls a function on that input, and if the result of that is Just x, it should return x; otherwise, it should return the original input.
In other words, this function (that I didn't know what to call):
foo :: (a -> Maybe a) -> a -> a
foo f x = fromMaybe x (f x)
Since it seems like a general-purpose function, I wondered if it wasn't already defined, so I asked on Twitter, and Chris Allen replied that it's ap fromMaybe.
That sounded promising, so I fired up GHCI and started experimenting:
Prelude Control.Monad Data.Maybe> :type ap
ap :: Monad m => m (a -> b) -> m a -> m b
Prelude Control.Monad Data.Maybe> :type fromMaybe
fromMaybe :: a -> Maybe a -> a
Prelude Control.Monad Data.Maybe> :type ap fromMaybe
ap fromMaybe :: (b -> Maybe b) -> b -> b
The type of ap fromMaybe certainly looks correct, and a couple of experiments seem to indicate that it has the desired behaviour as well.
But how does it work?
The fromMaybe function seems clear to me, and in isolation, I think I understand what ap does - at least in the context of Maybe. When m is Maybe, it has the type Maybe (a -> b) -> Maybe a -> Maybe b.
What I don't understand is how ap fromMaybe even compiles. To me, this expression looks like partial application, but I may be getting that wrong. If this is the case, however, I don't understand how the types match up.
The first argument to ap is m (a -> b), but fromMaybe has the type a -> Maybe a -> a. How does that match? Which Monad instance does the compiler infer that m is? How does fromMaybe, which takes two (curried) arguments, turn into a function that takes a single argument?
Can someone help me connect the dots?
But that use of ap is not in the context of Maybe. We're using it with a function, fromMaybe, so it's in the context of functions, where
ap f g x = f x (g x)
Among the various Monad instances we have
instance Monad ((->) r)
so it is
ap :: Monad m => m (a -> b) -> m a -> m b
fromMaybe :: r -> (Maybe r -> r)
ap :: (r -> (a -> b)) -> (r -> a) -> (r -> b)
ap f g x :: b
ap fromMaybe :: (r -> a) -> (r -> b) , a ~ Maybe r , b ~ r
because -> in types associates to the right: a -> b -> c ~ a -> (b -> c). Trying to plug the types together, we can only end up with that definition above.
And with (<*>) :: Applicative f => f (a -> b) -> f a -> f b, we can write it as (fromMaybe <*>), if you like this kind of graffiti:
#> :t (fromMaybe <*>)
(fromMaybe <*>) :: (r -> Maybe r) -> r -> r
As is rightfully noted in another answer here, when used with functions, <*> is just your good ole' S combinator. We can't very well have function named S in Haskell, so <*> is just a part of standard repertoire of the point-free style of coding. Monadic bind (more so, flipped), =<<, can be even more mysterious, but a pointfree coder just doesn't care and will happily use it to encode another, similar pattern,
(f =<< g) x = f (g x) x
in combinatory function calls, mystery or no mystery (zipWith (-) =<< drop 1 comes to mind).
Apologies for laconic and mechanical answer. I don't like cherry-picking things like Applicative or Monad, but I don't know where you're at. This is not my usual approach to teaching Haskell.
First, ap is really (<*>) under the hood.
Prelude> import Control.Monad
Prelude> import Data.Maybe
Prelude> import Control.Applicative
Prelude> :t ap
ap :: Monad m => m (a -> b) -> m a -> m b
Prelude> :t (<*>)
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
What does this mean? It means we don't need something as "strong" as Monad to describe what we're doing. Applicative suffices. Functor doesn't, though.
Prelude> :info Applicative
class Functor f => Applicative (f :: * -> *) where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
Prelude> :info Functor
class Functor (f :: * -> *) where
fmap :: (a -> b) -> f a -> f b
Here's ap/(<*>) with the Maybe Monad/Applicative:
Prelude> ap (Just (+1)) (Just 1)
Just 2
Prelude> (<*>) (Just (+1)) (Just 1)
Just 2
First thing to figure out is, which instance of the typeclass Applicative are we talking about?
Prelude> :t fromMaybe
fromMaybe :: a -> Maybe a -> a
Desugaring fromMaybe's type a bit gives us:
(->) a (Maybe a -> a)
So the type constructor we're concerned with here is (->). What does GHCi tell us about (->) also known as function types?
Prelude> :info (->)
data (->) a b -- Defined in ‘GHC.Prim’
instance Monad ((->) r) -- Defined in ‘GHC.Base’
instance Functor ((->) r) -- Defined in ‘GHC.Base’
instance Applicative ((->) a) -- Defined in ‘GHC.Base’
Hrm. What about Maybe?
Prelude> :info Maybe
data Maybe a = Nothing | Just a -- Defined in ‘GHC.Base’
instance Monad Maybe -- Defined in ‘GHC.Base’
instance Functor Maybe -- Defined in ‘GHC.Base’
instance Applicative Maybe -- Defined in ‘GHC.Base’
What happened with the use of (<*>) for Maybe was this:
Prelude> (+1) 1
2
Prelude> (+1) `fmap` Just 1
Just 2
Prelude> Just (+1) <*> Just 1
Just 2
Prelude> :t fmap
fmap :: Functor f => (a -> b) -> f a -> f b
Prelude> let mFmap = fmap :: (a -> b) -> Maybe a -> Maybe b
Prelude> (+1) `mFmap` Just 1
Just 2
Prelude> :t (<*>)
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
Prelude> let mAp = (<*>) :: Maybe (a -> b) -> Maybe a -> Maybe b
Prelude> :t (+1)
(+1) :: Num a => a -> a
Prelude> :t Just (+1)
Just (+1) :: Num a => Maybe (a -> a)
Prelude> Just (+1) `mAp` Just 1
Just 2
Okay, what about the function type's Functor and Applicative? One of the tricky parts here is that (->) has be to be partially applied in the type to be a Functor/Applicative/Monad. So your f becomes (->) a of the overall (->) a b where a is an argument type and b is the result.
Prelude> (fmap (+1) (+2)) 0
3
Prelude> (fmap (+1) (+2)) 0
3
Prelude> :t fmap
fmap :: Functor f => (a -> b) -> f a -> f b
Prelude> let funcMap = fmap :: (a -> b) -> (c -> a) -> c -> b
Prelude> -- f ~ (->) c
Prelude> (funcMap (+1) (+2)) 0
3
Prelude> :t (<*>)
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
Prelude> let funcAp = (<*>) :: (c -> a -> b) -> (c -> a) -> (c -> b)
Prelude> :t fromMaybe
fromMaybe :: a -> Maybe a -> a
Prelude> :t funcAp fromMaybe
funcAp fromMaybe :: (b -> Maybe b) -> b -> b
Prelude> :t const
const :: a -> b -> a
Prelude> :t funcAp const
funcAp const :: (b -> b1) -> b -> b
Not guaranteed to be useful. You can tell funcAp const isn't interesting just from the type and knowing how parametricity works.
Edit: speaking of compose, the Functor for (->) a is just (.). Applicative is that, but with an extra argument. Monad is the Applicative, but with arguments flipped.
Further whuttery: Applicative <*> for (->) a) is S and pure is K of the SKI combinator calculus. (You can derive I from K and S. Actually you can derive any program from K and S.)
Prelude> :t pure
pure :: Applicative f => a -> f a
Prelude> :t const
const :: a -> b -> a
Prelude> :t const
const :: a -> b -> a
Prelude> let k = pure :: a -> b -> a
Prelude> k 1 2
1
Prelude> const 1 2
1
I'm going to relabel the type arguments, for clarity.
ap :: Monad m => m (a -> b) -> m a -> m b
fromMaybe :: c -> Maybe c -> c
Which Monad instance does the compiler infer that m is?
((->) r) is a Monad. This is all functions that have type r as their argument, for some specific r.
So in the type:
ap :: Monad m => m (a -> b) -> m a -> m b
m ~ (c ->), a ~ Maybe c and b ~ c.
The return type, m a -> m b, expands to (c -> Maybe c) -> c -> c - which is the type of ap fromMaybe.
The monad you are looking for is (->) r or r -> _ if you prefer infix syntax.
Then the signature of ap expands to:
m (a -> b) -> m a -> m b =
(r -> (a -> b)) -> (r -> a) -> r -> b = -- now we use the signature of fromMaybe
(b -> (Maybe b -> b)) -> (b -> Maybe b) -> b -> b
Now if you consider ap fromMaybe as a partially applied function and voila you get the desired result.
Related
GHCi has :type <expr> to show the type of an expression:
Prelude> :t (<*>)
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
Can GHCi show the result after a substitution of any of the type variables? For example, let f = ((->) c), then
:t (<*>) :: ((->) c) (a->b) -> ((->) c) a -> ((->) c) b
(<*>) :: ((->) c) (a->b) -> ((->) c) a -> ((->) c) b
:: (c -> a -> b) -> (c -> a) -> c -> b
Is there a way to let GHCi work out these substitutions?
Yes, there are a few ways. Many operations make their type variables a part of their API, and you can observe this by turning on the right options and asking in the right way.
> :set -fprint-explicit-foralls
> :t +v (<*>)
(<*>)
:: forall (f :: * -> *).
Applicative f =>
forall a b. f (a -> b) -> f a -> f b
This actually doesn't look that special, but says something important: because the foralld type variables are not enclosed in braces, they can be the subject of type applications. (But you should trust the "braces"/"not braces" distinction only in :t +v queries! Normal :t munges type-application-availableness in a brittle way that may change from GHC version to GHC version.)
> :set -XTypeApplications
> :t (<*>) #((->) _)
(<*>) #((->) _)
:: forall {w} {a} {b}. (w -> a -> b) -> (w -> a) -> w -> b
Sometimes you will find a term where you cannot use type applications in this way. For example:
> :t +v \f x -> f <*> x
\f x -> f <*> x
:: forall {f :: * -> *} {a} {b}.
Applicative f =>
f (a -> b) -> f a -> f b
Here the braces indicate that there are no types available for type application. Are we out of luck? No, we can still use type holes to fill in only the parts we care about and ask GHC about the rest.
> :set -XPartialTypeSignatures
> :set -Wno-partial-type-signatures
> :t (\f x -> f <*> x) :: ((_ -> _) -> _)
(\f x -> f <*> x) :: ((_ -> _) -> _)
:: forall {w} {a} {b}. (w -> a -> b) -> (w -> a) -> w -> b
For example, typing :t ap in GHCi gives the result
ap :: Monad m => m (a -> b) -> m a -> m b
If I already know the Monad instance I'm going to use is ((->) r), how can I query for the type of ap for that specific instance?
As Lazersmoke said as a comment you can use the TypeApplications extension that was introduced in GHC 8.0.
In GHCi:
λ > :set -XTypeApplications
λ > import Control.Monad
λ > :t ap #((->) _)
ap #((->) _) :: (t -> a -> b) -> (t -> a) -> t -> b
You can use visible type application feature to specify parametric types. You can look at functions in more creative way: functions in Haskell can be applied to not only values of some types, but also to types of that values. But to pass type you should somehow specify (with prepending #) that you're passing types (because types are not first-class objects in Haskell yet).
So here how it works:
λ: :set -XTypeApplications
λ: :t ap #((->) Int)
ap #((->) Int) :: (Int -> a -> b) -> (Int -> a) -> Int -> b
The only limitation of such approach is that you can't use type variables in ghci, you should use specific types (Int instead of r) but this is not big deal.
ADVANCED SECTION
Well, actually you can, but it's tricky:
λ: :set -XExplicitForAll
λ: :set -XPartialTypeSignatures
λ: :set -XScopedTypeVariables
λ: :{
λ| foo :: forall r . _
λ| foo = ap #((->) r)
λ| :}
<interactive>:28:19: warning: [-Wpartial-type-signatures]
• Found type wildcard ‘_’
standing for ‘(r -> a -> b) -> (r -> a) -> r -> b’
λ: :t foo
foo :: (r -> a -> b) -> (r -> a) -> r -> b
UPD: You can actually use placeholders instead of type variables (see another answer). But if you want to specify exact names use approach from above.
λ: :t ap #((->) _)
ap #((->) _) :: (t -> a -> b) -> (t -> a) -> t -> b
/ADVANCED SECTION
One more thing to say about this approach: you should do something more if your functions have several type parameters and you want to specify exact one. Types are passed one by one from left to right just as simple arguments in some function like bar :: Int -> String -> Double. If you want to fix first argument of bar you should write bar 5 and if you want to fix second, then, well, you can write something like \n -> bar n "baz" but this doesn't work with type application. You need to know two things:
Order of types.
How to specify desired type.
Consider next function:
λ: :t lift
lift :: (Monad m, MonadTrans t) => m a -> t m a
We want be able to specify m and t type variables. Because Haskell has no named type variables (yet) you can't write :t lift {t=MaybeT} or :t lift {m=IO} unfortunately. So go back to two things.
To see order of types you should use some compiler options. Order of type arguments is specified by forall and you can do it manually. Otherwise type parameters will be sorted somehow by the compiler. Mere mortals can't see order of types for lift function but if you're aware of some high-level magic you can:
λ: :set -fprint-explicit-foralls
λ: :t lift
lift
:: forall {t :: (* -> *) -> * -> *} {a} {m :: * -> *}.
(Monad m, MonadTrans t) =>
m a -> t m a
And then you should use #_ to skip some types:
λ: :t lift #MaybeT
lift #MaybeT
:: forall {a} {m :: * -> *}. Monad m => m a -> MaybeT m a
λ: :t lift #_ #IO
lift #_ #IO
:: forall {t :: (* -> *) -> * -> *} {a}.
MonadTrans t =>
IO a -> t IO a
λ: :t lift #_ #_ #Int
lift #_ #_ #Int
:: forall {t :: (* -> *) -> * -> *} {t1 :: * -> *}.
(Monad t1, MonadTrans t) =>
t1 Int -> t t1 Int
Well, this is really mystery for me why m is shown as third argument in forall but should be passed as second but I'm still not aware of all magic.
This is just a hack, but you could always do something like:
:t ap . (id :: ((->) r a) -> ((->) r a))
or
:t \x y -> (id :: ...) (ap x y)
interestingly
Prelude Control.Monad> type Reader = (->) r
Prelude Control.Monad> :t ap . (id :: Reader r a -> Reader r a)
ap . (id :: Reader r a -> Reader r a)
:: Reader r (a -> b) -> (r -> a) -> r -> b
differs from
Prelude Control.Monad> :t \x y -> (id :: Reader r a -> Reader r a) (ap x y)
\x y -> (id :: Reader r a -> Reader r a) (ap x y)
:: (r -> a1 -> a) -> (r -> a1) -> Reader r a
in what ghc recognizes as the synonym Reader r a
I have stumbled on this piece of code fold ((,) <$> sum <*> product) with type signature :: (Foldable t, Num a) => t a -> (a, a) and I got completely lost.
I know what it does, but I don't know how. So I tried to break it into little pieces in ghci:
λ: :t (<$>)
(<$>) :: Functor f => (a -> b) -> f a -> f b
λ: :t (,)
(,) :: a -> b -> (a, b)
λ: :t sum
sum :: (Foldable t, Num a) => t a -> a
Everything is okay, just basic stuff.
λ: :t (,) <$> sum
(,) <$> sum :: (Foldable t, Num a) => t a -> b -> (a, b)
And I am lost again...
I see that there is some magic happening that turns t a -> a into f a but how it is done is mystery to me. (sum is not even instance of Functor!)
I have always thought that f a is some kind of box f that contains a but it looks like the meaning is much deeper.
The functor f in your example is the so-called "reader functor", which is defined like this:
newtype Reader r = Reader (r -> a)
Of course, in Haskell, this is implemented natively for functions, so there is no wrapping or unwrapping at runtime.
The corresponding Functor and Applicative instances look like this:
instance Functor f where
fmap :: (a -> b) -> (r -> a)_-> (r -> b)
fmap f g = \x -> f (g x) -- or: fmap = (.)
instance Applicative f where
pure :: a -> (r -> a) -- or: a -> r -> a
pure x = \y -> x -- or: pure = const
(<*>) :: (r -> a -> b) -> (r -> a) -> (r -> b)
frab <*> fra = \r -> frab r (fra r)
In a way, the reader functor is a "box" too, like all the other functors, having a context r which produces a type a.
So let's look at (,) <$> sum:
:t (,) :: a -> b -> (a, b)
:t fmap :: (d -> e) -> (c -> d) -> (c -> e)
:t sum :: Foldable t, Num f => t f -> f
We can now specialize the d type to a ~ f, e to b -> (a, b) and c to t f. Now we get:
:t (<$>) -- spcialized for your case
:: Foldable t, Num f => (a -> (b -> (a, b))) -> (t f -> f) -> (t f -> (b -> (a, b)))
:: Foldable t, Num f => (f -> b -> (f, b)) -> (t f -> f) -> (t f -> b -> (f, b))
Applying the functions:
:t (,) <$> sum
:: Foldable t, Num f => (t f -> b -> (f, b))
Which is exactly what ghc says.
The short answer is that f ~ (->) (t a). To see why, just rearrange the type signature for sum slightly, using -> as a prefix operator instead of an infix operator.
sum :: (Foldable t, Num a) => (->) (t a) a
~~~~~~~~~~
f
In general, (->) r is a functor for any argument type r.
instance Functor ((->) r) where
fmap = (.)
It's easy to show that (.) is the only possible implementation for fmap here by plugging ((->) r) into the type of fmap for f:
fmap :: (a -> b) -> f a -> f b
:: (a -> b) -> ((->) r) a -> ((->) r) b
:: (a -> b) -> (r -> a) -> (r -> b)
This is the type signature for composition, and composition is the unique function that has this type signature.
Since Data.Functor defines <$> as an infix version of fmap, we have
(,) <$> sum == fmap (,) sum
== (.) (,) sum
From here, it is a relatively simple, though tedious, job of confirming that the resulting type is, indeed, (Foldable t, Num a) => t a -> b -> (a, b). We have
(b' -> c') -> (a' -> b') -> (a' -> c') -- composition
b' -> c' ~ a -> b -> (a,b) -- first argument (,)
a' -> b' ~ t n -> n -- second argument sum
----------------------------------------------------------------
a' ~ t n
b' ~ a ~ n
c' ~ a -> b -> (a,b)
----------------------------------------------------------------
a' -> c' ~ t a -> b -> (a,b)
Looking at Haskell's bind:
Prelude> :t (>>=)
(>>=) :: Monad m => m a -> (a -> m b) -> m b
I was confused by the following example:
Prelude> let same x = x
Prelude> [[1]] >>= \x -> same x
[1]
Looking at >>='s signature, how does \x -> same x type check with a -> m b?
I would've expected \x -> same x to have produced a [b] type, since the Monad m type here is [], as I understand.
You say
I would've expected \x -> same x to have produced a [b] type, since the Monad m type here is [], as I understand.
and so it does because it is.
We have
[[1]] >>= \ x -> same x
=
[[1]] >>= \ x -> x
[[Int]] [Int] -> [Int] :: [Int]
[] [Int] [Int] -> [] Int :: [] Int
m a a m b m b
Sometimes [] is describing a kind of "nondeterminism" effect. Other times, [] is describing a container-like data structure. The fact that it's difficult to tell the difference between which of these two purposes is being served is a feature of which some people are terribly proud. I'm not ready to agree with them, but I see what they're doing.
Looking at >>='s signature, how does \x -> same x type check with a -> m b?
It's actually very simple. Look at the type signatures:
same :: x -> x
(>>=) :: Monad m => m a -> (a -> m b) -> m b
(>>= same) :: Monad m => m a -> (a -> m b) -> m b
|________|
|
x -> x
Therefore:
x := a
-- and
x := m b
-- and by transitivity
a := x := m b
-- or
a := m b
Hence:
(>>= same) :: Monad m => m (m b) -> m b
This is just the join function from the Control.Monad module, and for the list monad it is the same as the concat function. Thus:
[[1]] >>= \x -> same x
-- is the same as the following via eta reduction
[[1]] >>= same
-- is the same as
(>>= same) [[1]]
-- is the same as
join [[1]]
-- is the same as
concat [[1]]
-- evaluates to
[1]
I would've expected \x -> same x to have produced a [b] type, since the Monad m type here is [], as I understand.
Indeed, it does. The \x -> same x function which has the type x -> x is specialized to the type [b] -> [b] as I explained above. Hence, (>>= same) is of the type [[b]] -> [b] which is the same as the concat function. It flattens a list of lists.
The concat function is a specialization of the join function which flattens a nested monad.
It should be noted that a monad can be defined in terms of either >>= or fmap and join. To quote Wikipedia:
Although Haskell defines monads in terms of the return and >>= functions, it is also possible to define a monad in terms of return and two other operations, join and fmap. This formulation fits more closely with the original definition of monads in category theory. The fmap operation, with type Monad m => (a -> b) -> m a -> m b, takes a function between two types and produces a function that does the “same thing” to values in the monad. The join operation, with type Monad m => m (m a) -> m a, “flattens” two layers of monadic information into one.
The two formulations are related as follows:
fmap f m = m >>= (return . f)
join n = n >>= id
m >>= g ≡ join (fmap g m)
Here, m has the type Monad m => m a, n has the type Monad m => m (m a), f has the type a -> b, and g has the type Monad m => a -> m b, where a and b are underlying types.
The fmap function is defined for any functor in the category of types and functions, not just for monads. It is expected to satisfy the functor laws:
fmap id ≡ id
fmap (f . g) ≡ (fmap f) . (fmap g)
The return function characterizes pointed functors in the same category, by accounting for the ability to “lift” values into the functor. It should satisfy the following law:
return . f ≡ fmap f . return
In addition, the join function characterizes monads:
join . fmap join ≡ join . join
join . fmap return ≡ join . return = id
join . fmap (fmap f) ≡ fmap f . join
Hope that helps.
As a few people have commented, you've found a really cute property about monads here. For reference, let's look at the signature for bind:
:: Monad m => m a -> (a -> m b) -> m b
In your case, the type a === m b as you have a [[a]] or m (m a). So, if you rewrite the signature of the above bind operation, you get:
:: Monad m => m (m b) -> ((m b) -> m b) -> m b
I mentioned that this is cute, because by extension, this works for any nested monad. e.g.
:: [[b]] -> ([b] -> [b]) -> [b]
:: Maybe (Maybe b) -> (Maybe b -> Maybe b) -> Maybe b
:: Reader (Reader b) -> (Reader b -> Reader b) -> Reader b
If you look at the function that get's applied here, you'll see that it's the identity function (e.g. id, same, :: forall a. a -> a).
This is included in the standard libraries for Haskell, as join. You can look at the source here on hackage. You'll see it's implemented as bind id, or \mma -> mma >>= id, or (=<<) id
As you say m is []. Then a is [Integer] (ignoring the fact that numbers are polymorphic for simplicity's sake) and b is Integer. So a -> m b becomes [Integer] -> [Integer].
First: we should use the standard version of same, it is called id.
Now, let's rename some type variables
id :: (a'' ~ a) => a -> a''
What this means is: the signature of id is that of a function mapping between two types, with the extra constraint that both types be equal. That's all – we do not require any particular properties, like “being flat”.
Why the hell would I write it this way? Well, if we also rename some of the variables in the bind signature...
(>>=) :: (Monad m, a'~m a, a''~m b) => a' -> (a -> a'') -> a''
...then it is obvious how we can plug the id, as the type variables have already been named accordingly. The type-equality constraint a''~a from id is simply taken to the compound's signature, i.e.
(>>=id) :: (Monad m, a'~m a, a''~m b, a''~a) => a' -> a''
or, simplifying that,
(>>=id) :: (Monad m, a'~m a, m b~a) => a' -> m b
(>>=id) :: (Monad m, a'~m (m b)) => a' -> m b
(>>=id) :: (Monad m) => m (m b) -> m b
So what this does is, it flattens a nested monad to a single application of that same monad. Quite simple, and as a matter of fact this is one the “more fundamental” operation: mathematicians don't define the bind operator, they instead define two morphisms η :: a -> m a (we know that, it's return) and μ :: m (m a) -> m a – yup, that's the one you've just discovered. In Haskell, it's called join.
The monad here is [a] and the example is pointlessly complicated. This’ll be clearer:
Prelude> [[1]] >>= id
[1]
just as
Prelude> [[1]] >>= const [2]
[2]
i.e. >>= is concatMap and is concat when used with id.
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.
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
Note that, in
(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c
m is static -- You're trying to substitute both [] and Maybe for m in the definition -- that won't type check.
You can use <=< to compose functions of the form a -> m b where m is a single monad. Note that you can use different type arguments though, you don't need to be constrained to the polymorphic a.
Here's an example of using this pattern constrained to the list monad:
f :: Int -> [Int]
f x = [x, x^2]
g :: Int -> [String]
g 0 = []
g x = [show x]
λ> :t g <=< f
g <=< f :: Int -> [String]
λ> g <=< f $ 10
["10","100"]
You can't mix monads together. When you see the signature
(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c
The Monad m is only a single Monad, not two different ones. If it were, the signature would be something like
(<=<) :: (Monad m1, Monad m2) => (b -> m2 c) -> (a -> m1 b) -> a -> m2 c
But this is not the case, and in fact would not really be possible in general. You can do something like
f :: Int -> Maybe Int
f 0 = Just 0
f _ = Nothing
g :: Int -> Maybe Int
g x = if even x then Just x else Nothing
h :: Int -> Maybe Int
h = f <=< g