I have a practice question, where I'm given a function:
sequence :: Applicative f => [f a] -> f[a]
sequence = foldr (_hole (:)) (pure [])
and the question says:
"What type is required for the function that needs to be placed at
_hole in the following expression? Also give a definition for the
expression using and <$> and <*>".
I'm having issue understanding what the question is asking. So for what I've tried, i assume that I'm required to specify the operator since it's using foldr so i assume its something like sequence = foldr((+) (:)) (pure[]).
Then for the definition of the expression, i wrote something like:
sequence :: <*> f => [f a] -> f[a]
sequence = foldr <$> pure []
I'm pretty sure I'm not 100% correct so would appreciate some help on this on any corrections.
The exercise wants you to assume that some value _hole is defined somewhere, and that the code above type checks. Then, the goal is to determine what would be the type of that _hole. Then, it would ask a possible definition for _hole.
For instance, if we were given
foo :: Int
foo = 3 + _hole
the answer should be _hole :: Int, since that's what we need to make the code above to work. For the definition _hole = 2 is OK.
Instead, in
foo :: Int -> Bool
foo = const _hole "hello" True
then we need _hole :: Bool -> Int -> Bool and for instance _hole = \b i -> b.
Your own code is more complex, so it's better to write down all the steps:
sequence :: Applicative f => [f a] -> f[a]
sequence = foldr (_hole (:)) (pure [])
Here foldr is used, which (on lists) has type
foldr :: (b -> c -> c) -> c -> [b] -> c
To type check, the arguments must have type
_hole (:) :: b -> c -> c
pure [] :: c
the result of foldr, being called with only two arguments is
sequence :: [b] -> c
since this must match the type of sequence above, we get
[b] = [f a]
c = f [a]
Hence, b = f a and
_hole (:) :: f a -> f [a] -> f [a]
pure [] :: f [a]
The pure [] part type checks as it is. For the other, we need
_hole :: (type of (:)) -> f a -> f [a] -> f [a]
i.e. since (:) :: d -> [d] -> [d] for any d, we get
_hole :: (d -> [d] -> [d]) -> f a -> f [a] -> f [a]
where d can be picked arbitrarily. It is "natural", though, to pick d=a, so that we get
_hole :: (a -> [a] -> [a]) -> f a -> f [a] -> f [a]
Now, we need to write a definition _hole f x y = ?? in terms of <$> and <*>. Essentially, we need to re-implement liftA2 from the library. You should now be able to solve this last part.
Let's do it step by step, gradually discovering the types of the entities involved in our definition. We are given
sequence :: Applicative f => [f a] -> f [a] -- (1)
sequence = foldr (_hole (:)) (pure []) -- (2)
so that sequence = mksequence g for some g:
mksequence g xs = foldr (g (:)) (pure []) xs -- (3)
mksequence g [a,b,...,n] = r where -- (4)
r = g (:) a $ g (:) b $ ... $ g (:) n (pure []) -- (5)
mksequence g [a] = g (:) a (pure []) -- (6)
mksequence g [] = pure [] -- (7)
-- [a,b,...,n] :: [f a] <-(4,1) -- (8)
-- a,b,...,n :: f a <-(8) -- (9)
-- r :: f [a] <-(4,1) -- (10)
-- pure [] :: f [a] <-(7,1) -- (11)
-- g (:) :: f a -> f [a] -> f [a] <-(6,8,11,1)
Finally, we've found the type of g (:)! Compare it with
(<*>) :: f (a -> t) -> f a -> f t , _A :: f (a -> t)
(_A <*> _C) :: f t , _C :: f a
(_B <*> _C) :: f (t -> s) , _B :: f (a -> (t -> s))
((_B <*> _C) <*> _D) :: f s , _D :: f t
So that we have,
\ _B _C _D -> ((_B <*> _C) <*> _D)
:: f (a -> (t -> s)) -> f a -> f t -> f s
g ((:) :: a -> [a] -> [a]) :: f a -> f [a] -> f [a]
The signatures nearly match! With just a little nudge we have
g (:) = (\ _B _C _D -> ((_B <*> _C) <*> _D)) (pure (:))
and so, generalizing,
g f2 fa ft = pure f2 <*> fa <*> ft
because (<*>) associates to the left. Re-checking the types,
g f2 fa ft = pure f2 <*> fa <*> ft
= f2 <$> fa <*> ft
-- fa :: f a
-- f2 :: a -> t -> s
-- f2 <$> fa :: f (t -> s)
-- ft :: f t
-- (f2 <$> fa) <*> ft :: f s
In fact this definition already exists, and is named liftA2 -- for "lifting" a binary function (f2) into an applicative "context" (f):
f2 :: a -> t -> s
liftA2 f2 :: f a -> f t -> f s
Related
I have this pair of functions
(,) <$> length :: Foldable t => t a -> b -> (Int, b)
and,
head :: [a] -> a
I would like to understand the type of
(,) <$> length <*> head
In (<*>) :: Applicative f => f (a -> b) -> f a -> f b type signature,
f :: (->) [a]
a :: b
b :: (Int -> b)
So, the instantiated type would be:
(->) [a] (Int, b)
However, I found out really its type is:
(->) [a] (Int, a)
Two questions, if I may:
Why is the b switched for an a ?
What's the step by step process in this type signature calculation ?
Let's keep using the signature
(,) <$> length :: Foldable t => t a -> b -> (Int, b)
But change
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
to
(<*>) :: Applicative f => f (x -> y) -> f x -> f y
so it doesn't get confusing. Clearly f ~ (->) [a] (assuming we're using the list instance of foldable) as you noticed, and thus x -> y ~ b -> (Int, b), so x ~ b and y ~ (Int, b). This is the part you missed, likely due to having confusing naming: the second argument is f x or [a] -> b, and you pass in head, which is [a] -> a. This forces b to become the same as a, otherwise the types wouldn't work out. The result is f y, or [a] -> (Int, b), except b is now a, giving you the [a] -> (Int, a) signature.
One way to derive the type of (,) <$> length <*> head is to abstract over length and head and consider instead the resulting lambda expression
\l -> \h -> (,) <$> l <*> h
of type
Applicative f => f a -> f b -> f (a, b)
with the types [x] -> Int and [x] -> x of length and head respectively we require
f a ~ [x] -> Int
f b ~ [x] -> x
and thus
f ~ (->) [x] -- hom-functor aka Reader
a ~ Int
b ~ x
which yields
([x] -> Int) -> ([x] -> x) -> ([x] -> (Int, x))
as type for the above lambda expression.
Another way to derive the type of (,) <$> length <*> head is to work it out progressively by applying the definitions at every step:
(,) :: a -> b -> (a, b)
-- (<$>) :: (a -> c ) -> f a -> f c
(,) <$> :: f a -> f (b -> (a, b)) -- f a -> f c
-- length :: [t] -> Int
(,) <$> length :: [t] -> (b -> (Int, b))
-- (<*>) :: f (s -> q ) -> f s -> f q
(,) <$> length <*> :: ([t] -> b) -> ([t] -> (Int, b)) -- f s -> f q
-- head :: [t] -> t
(,) <$> length <*> head :: [t] -> (Int, t)
The trickiest part is to correctly apply (->) [t] for f in the third and fourth step.
We can try to arrive at some more easily understood formulation first, so that its type becomes "obvious". We have
(,) <$> length <*> head
=
pure (,) <*> length <*> head
=
liftA2 (,) length head
for any Applicative, by the Applicative laws and the definition of liftA2.
So we have (,) combining the contained / carried / produced results from the applicative values length and head:
(,)
/ \
/ \
length head
But length and head are functions, and for functions we have
(,)
/ \
/ \
length head
\ /
\ /
x
i.e.
liftA2 (,) length head x
=
(,) (length x) (head x)
by the definition of the (->)'s Applicative instance.
Thus the type of (,) <$> length <*> head is the type of liftA2 (,) length head is the type of \ x -> (length x , head x). And that is "obviously" "just" [a] -> (Int , a).
GHCi concurs:
> :t \ x -> (length x , head x)
\ x -> (length x , head x) :: [t] -> (Int, t)
> :t (,) <$> length <*> head
(,) <$> length <*> head :: [a] -> (Int, a)
length :: Foldable t => t a -> Int is defined for any Foldable but head :: [a] -> a works on lists specifically, so length's type becomes specialized as [a] -> Int.
And head produces the same type that the elements of the input list have:
(Int,a) ~ (,) Int a
/ \ | |
/ \ | |
length \ :: [a] -> Int |
\ head :: [a] -> a
\ / |
\ / |
[a] ~ [a]
So there's no "switching". Everything flows.
class Applicative f => Monad f where
return :: a -> f a
(>>=) :: f a -> (a -> f b) -> f b
(<*>) can be derived from pure and (>>=):
fs <*> as =
fs >>= (\f -> as >>= (\a -> pure (f a)))
For the line
fs >>= (\f -> as >>= (\a -> pure (f a)))
I am confused by the usage of >>=. I think it takes a functor f a and a function, then return another functor f b. But in this expression, I feel lost.
Lets start with the type we're implementing:
(<*>) :: Monad f => f (a -> b) -> f a -> f b
(The normal type of <*> of course has an Applicative constraint, but here we're trying to use Monad to implement Applicative)
So in fs <*> as = _, fs is an "f of functions" (f (a -> b)), and as is an "f of as".
We'll start by binding fs:
(<*>) :: Monad f => f ( a -> b) -> f a -> f b
fs <*> as
= fs >>= _
If you actually compile that, GHC will tell us what type the hole (_) has:
foo.hs:4:12: warning: [-Wtyped-holes]
• Found hole: _ :: (a -> b) -> f b
Where: ‘a’, ‘f’, ‘b’ are rigid type variables bound by
the type signature for:
(Main.<*>) :: forall (f :: * -> *) a b.
Monad f =>
f (a -> b) -> f a -> f b
at foo.hs:2:1-45
That makes sense. Monad's >>= takes an f a on the left and a function a -> f b on the right, so by binding an f (a -> b) on the left the function on the right gets to receive an (a -> b) function "extracted" from fs. And provided we can write a function that can use that to return an f b, then the whole bind expression will return the f b we need to meet the type signature for <*>.
So it'll look like:
(<*>) :: Monad f => f ( a -> b) -> f a -> f b
fs <*> as
= fs >>= (\f -> _)
What can we do there? We've got f :: a -> b, and we've still got as :: f a, and we need to make an f b. If you're used to Functor that's obvious; just fmap f as. Monad implies Functor, so this does in fact work:
(<*>) :: Monad f => f ( a -> b) -> f a -> f b
fs <*> as
= fs >>= (\f -> fmap f as)
It's also, I think, a much easier way to understand the way Applicative can be implemented generically using the facilities from Monad.
So why is your example written using another >>= and pure instead of just fmap? It's kind of harkening back to the days when Monad did not have Applicative and Functor as superclasses. Monad always "morally" implied both of these (since you can implement Applicative and Functor using only the features of Monad), but Haskell didn't always require there to be these instances, which leads to books, tutorials, blog posts, etc explaining how to implement these using only Monad. The example line given is simply inlining the definition of fmap in terms of >>= and pure (return)1.
I'll continue to unpack as if we didn't have fmap, so that it leads to the version you're confused by.
If we're not going to use fmap to combine f :: a -> b and as :: f a, then we'll need to bind as so that we have an expression of type a to apply f to:
(<*>) :: Monad f => f ( a -> b) -> f a -> f b
fs <*> as
= fs >>= (\f -> as >>= (\a -> _))
Inside that hole we need to make an f b, and we have f :: a -> b and a :: a. f a gives us a b, so we'll need to call pure to turn that into an f b:
(<*>) :: Monad f => f ( a -> b) -> f a -> f b
fs <*> as
= fs >>= (\f -> as >>= (\a -> pure (f a)))
So that's what this line is doing.
Binding fs :: f (a -> b) to get access to an f :: a -> b
Inside the function that has access to f it's binding as to get access to a :: a
Inside the function that has access to a (which is still inside the function that has access to f as well), call f a to make a b, and call pure on the result to make it an f b
1 You can implement fmap using >>= and pure as fmap f xs = xs >>= (\x -> pure (f x)), which is also fmap f xs = xs >>= pure . f. Hopefully you can see that the inner bind of your example is simply inlining the first version.
Applicative is a Functor. Monad is also a Functor. We can see the "Functorial" values as standing for computations of their "contained" ⁄ produced pure values (like IO a, Maybe a, [] a, etc.), as being the allegories of ⁄ metaphors for the various kinds of computations.
Functors describe ⁄ denote notions ⁄ types of computations, and Functorial values are reified computations which are "run" ⁄ interpreted in a separate step which is thus akin to that famous additional indirection step by adding which, allegedly, any computational problem can be solved.
Both fs and as are your Functorial values, and bind ((>>=), or in do notation <-) "gets" the carried values "in" the functor. Bind though belongs to Monad.
What we can implement in Monad with (using return as just a synonym for pure)
do { f <- fs ; -- fs >>= ( \ f -> -- fs :: F (a -> b) -- f :: a -> b
a <- as ; -- as >>= ( \ a -> -- as :: F a -- a :: a
return (f a) -- return (f a) ) ) -- f a :: b
} -- :: F b
( or, with MonadComprehensions,
[ f a | f <- fs, a <- as ]
), we get from the Applicative's <*> which expresses the same computation combination, but without the full power of Monad. The difference is, with Applicative as is not dependent on the value f there, "produced by" the computation denoted by fs. Monadic Functors allow such dependency, with
[ bar x y | x <- xs, y <- foo x ]
but Applicative Functors forbid it.
With Applicative all the "computations" (like fs or as) must be known "in advance"; with Monad they can be calculated -- purely -- based on the results of the previous "computation steps" (like foo x is doing: for (each) value x that the computation xs will produce, new computation foo x will be (purely) calculated, the computation that will produce (some) y(s) in its turn).
If you want to see how the types are aligned in the >>= expressions, here's your expression with its subexpressions named, so they can be annotated with their types,
exp = fs >>= g -- fs >>=
where g f = xs >>= h -- (\ f -> xs >>=
where h x = return (f x) -- ( \ x -> pure (f x) ) )
x :: a
f :: a -> b
f x :: b
return (f x) :: F b
h :: a -> F b -- (>>=) :: F a -> (a -> F b) -> F b
xs :: F a -- xs h
-- <-----
xs >>= h :: F b
g f :: F b
g :: (a -> b) -> F b -- (>>=) :: F (a->b) -> ((a->b) -> F b) -> F b
fs :: F (a -> b) -- fs g
-- <----------
fs >>= g :: F b
exp :: F b
and the types of the two (>>=) applications fit:
(fs :: F (a -> b)) >>= (g :: (a -> b) -> F b)) :: F b
(xs :: F a ) >>= (h :: (a -> F b)) :: F b
Thus, the overall type is indeed
foo :: F (a -> b) -> F a -> F b
foo fs xs = fs >>= g -- foo = (<*>)
where g f = xs >>= h
where h x = return (f x)
In the end, we can see monadic bind as an implementation of do, and treat the do notation
do {
abstractly, axiomatically, as consisting of the lines of the form
a <- F a ;
b <- F b ;
......
n <- F n ;
return (foo a b .... n)
}
(with a, F b, etc. denoting values of the corresponding types), such that it describes the overall combined computation of the type F t, where foo :: a -> b -> ... -> n -> t. And when none of the <-'s right-hand side's expressions is dependent on no preceding left-hand side's variable, it's not essentially Monadic, but just an Applicative computation that this do block is describing.
Because of the Monad laws it is enough to define the meaning of do blocks with just two <- lines. For Functors, just one <- line is allowed ( fmap f xs = do { x <- xs; return (f x) }).
Thus, Functors/Applicative Functors/Monads are EDSLs, embedded domain-specific languages, because the computation-descriptions are themselves values of our language (those to the right of the arrows in do notation).
Lastly, a types mandala for you:
T a
T (a -> b)
(a -> T b)
-------------------
T (T b)
-------------------
T b
This contains three in one:
F a A a M a
a -> b A (a -> b) a -> M b
-------------- -------------- -----------------
F b A b M b
You can define (<*>) in terms of (>>=) and return because all monads are applicative functors. You can read more about this in the Functor-Applicative-Monad Proposal. In particular, pure = return and (<*>) = ap is the shortest way to achieve an Applicative definition given an existing Monad definition.
See the type signatures for (<*>), ap and (>>=):
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
ap :: Monad m => m (a -> b) -> m a -> m b
(>>=) :: Monad m => m a -> (a -> m b) -> m b
The type signature for (<*>) and ap are nearly equivalent. Since ap is written using do-notation, it is equivalent to some use of (>>=). I'm not sure this helps, but I find the definition of ap readable. Here's a rewrite:
ap m1 m2 = do { x1 <- m1; x2 <- m2; return (x1 x2) }
≡ ap m1 m2 = do
x1 <- m1
x2 <- m2
return (x1 x2)
≡ ap m1 m2 =
m1 >>= \x1 ->
m2 >>= \x2 ->
return (x1 x2)
≡ ap m1 m2 = m1 >>= \x1 -> m2 >>= \x2 -> return (x1 x2)
≡ ap mf ma = mf >>= (\f -> ma >>= (\a -> pure (f a)))
Which is your definition. You could show that this definition upholds the applicative functor laws, since not everything defined in terms of (>>=) and return does that.
could you explain how we go from :
Prelude Data.Monoid> :t (.)
(.) :: (b -> c) -> (a -> b) -> a -> c
Prelude Data.Monoid> :t (:)
(:) :: a -> [a] -> [a]
to that :
Prelude Data.Monoid> :t (.)(:)
(.)(:) :: (a1 -> a2) -> a1 -> [a2] -> [a2]
More in general, I'm sometimes afraid of (.) like I don't feel it intuitively, if you have some tricks to share to better feel it, it's welcome :-)
First, let's rename some things and put parenthesis:
(:) :: d -> ([d] -> [d])
Now, in the expresstion (.) (:) the (:) is the first argument of (.). The first argument of (.) should have type b -> c. Thus,
b -> c = d -> ([d] -> [d])
which means
b = d
c = [d] -> [d]
The result of (.) (:) has type (a -> b) -> a -> c. Putting our b and c in, we get
(a -> d) -> a -> ([d] -> [d])
This is exactly what ghci told you, except for the type variables renamed as a1 = a and a2 = d.
Well, let us do the type inference. We thus have two function:
(.) :: (b -> c) -> (a -> b) -> a -> c
(:) :: d -> [d] -> [d]
We here use d since the a in (.) is not per se the a in (:), so we avoid confusion by using two separate type variables.
The type signatures in a more canonic form are:
(.) :: (b -> c) -> ((a -> b) -> (a -> c))
(:) :: d -> ([d] -> [d])
So now since (:) is the argument of a function application with (.) as function, we know that the type of (:) is the type of the parameter of (.), so that means that d -> ([d] -> [d]) ~ (b -> c) (here the tilde ~ means that it is the same type). So therefore we know that:
b -> c
~ d -> ([d] -> [d])
---------------------
b ~ d, c ~ [d] -> [d]
So that means that the b in the type signature of (.) is the same type as d in the type signature of (:), and that c ~ [d] -> [d].
So the as a result, we get:
(.) (:) :: (a -> b) -> (a -> c))
= (.) (:) :: (a -> d) -> (a -> ([d] -> [d])))
= (.) (:) :: (a -> d) -> (a -> [d] -> [d])
= (.) (:) :: (a -> d) -> a -> [d] -> [d]
Writing (.) (:) as an operator section, ((:) .), emphasises a bit that it postcomposes (:) with some other function (i.e. it modifies a function by applying (:) to its result -- \g -> (g .) is fmap for functions). Symmetrically, (. (:)) precomposes (:) with some other function (\f -> (. f) is contramap for functions -- cf. the Op newtype).
(.) is nothing to fear. It is a most natural thing.
Imagine you define an abstract class of "connections":
class Connecting conn where
plug :: conn a b -> conn b c -> conn a c
noop :: conn a a
conn a b is a type of something which is connecting a point a to a point b. Given the possibility of connecting a to b, and b to c, it most naturally gives us the possibility of connecting a to c by just plugging the two somethings together. Also, any point which can be connected to another, and can get connected to, can obviously be considered connected to itself with absolutely no effort.
Functions are connecting. Just use the output of one as the input of another. If we have such two compatible functions, plugging them in that way gives us a combined connection.
Functions are Connecting:
instance Connecting (->) where
-- plug :: (->) a b -> (->) b c -> (->) a c
(plug f g) x = g (f x)
-- noop :: (->) a a
noop x = x -- what else? seriously. All we have is x.
Interesting thing about that plug :: (->) a b -> (->) b c -> (->) a c. That order of arguments is most fitting when we think about the types involved. But looking at its definition, we'd prefer it be defined as
gulp :: (->) b c -> (->) a b -> (->) a c
(gulp g f) x = g (f x)
Now the definition makes most sense, but the type feels a bit tortured.
Never mind that, we can have both:
(f :: a -> b) >>> (g :: b -> c) :: -- ...
a -> c
(g :: b -> c) <<< (f :: a -> b) :: -- ...
a ->
c
Coincidentally, <<< is also known as (.).
It is also clear that we have (.) = (<<<) = flip (>>>), so (g . f) x = g (f x) = (f >>> g) x.
Presented with g . f, it is often easier to deal with the equivalent expression f >>> g, types-wise. Just align the types, vertically,
(:) :: b -> ([b] -> [b])
f :: a -> b
f >>> (:) :: a -> ([b] -> [b])
so that
(>>> (:)) :: (a -> b) -- = ((:) <<<) = ((:) .) = (.) (:)
-> a -> ([b] -> [b])
because (>>> (:)) = (\f -> (f >>> (:))).
Which is (\f -> ((:) <<< f)) = (\f -> ((:) . f)) = ((:) .) = (.) (:).
edit: for instance, the type of (Endo . (:)) = ((:) >>> Endo) is easily arrived at, with:
Endo :: ( b -> b ) -> Endo b
(:) :: a -> ([a] -> [a]) -- b ~ [a]
(:) >>> Endo :: a -> Endo [a]
For more about Endo, try both :t Endo and :i Endo at GHCi prompt, and read up on Haskell's record syntax, if you need to.
Given value f with type :: Applicative f => f (a -> b -> c), What's the best way to map arguments to the inner function.
So far I've found the following:
(\x -> x a b) <$> f
(flip ($ a) b) <$> f
($ b) <$> ($ a) <$> f
I guess my question is why Haskell doesn't have a :: a -> b -> (a -> b -> c) -> c function. Or does it?
The Applicative class has the <*> operator (usually pronounced "ap", and is equivalent to Control.Monad.ap for most Monads), which combined with the <$> operator (itself just an infix alias for fmap) lets you write code like
-- f :: a -> b -> c
-- fa :: Applicative f => f a
-- fb :: Applicative f => f b
f <$> fa <*> fb :: Applicative f => f c
If you need to apply pure arguments, then use the pure method of the Applicative class:
-- f :: a -> b -> c
-- a :: a
-- b :: b
f <$> pure a <*> pure b :: Applicative f => f c
An example might be
sumOfSquares :: Num a => a -> a -> a
sumOfSquares a b = a * a + b * b
> sumOfSquares <$> Just 1 <*> Just 2
Just 5
> sumOfSquares <$> Just 1 <*> Nothing
Nothing
> sumOfSquares <$> pure 1 <*> pure 2 :: Maybe Int
5
> sumOfSquares <$> readLn <*> readLn :: IO Int
1<ENTER>
2<ENTER>
5
The Applicative f => f (a -> b -> c) is being constructed by f <$> here, so if you already had something like
> let g :: IO (Int -> Int -> Int); g = undefined
Then you could just use it as
> g <*> pure 1 <*> pure 2
The <*> operator has the type
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
so if your function has type x -> y -> z, then a ~ x and b ~ y -> z, so repeated application of <*> (get it?) passes more arguments to your wrapped function.
We've got
(<$>) :: Functor f => (a -> b) -> f a -> f b
But you want the opposite
(>$<) :: Functor f => f (a -> b) -> a -> f b
Which we can easily define:
(>$<) f a = ($a) <$> f
So given
f :: Functor f => f (a -> b -> c)
a :: a
b :: b
Then
f >$< a :: f (b -> c)
f >$< a >$< b :: f c
This isn't as idiomatic as <*>, but it works for all Functors, not just Applicatives, which is nice.
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