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.
Related
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
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.
When applying the list monad bind function to a simple list and identity function:
[[1,2],[3,4]] >>= \x -> x
I get
[1,2,3,4]
However, the definition of the Monad type class:
class Monad m where
(>>=) :: m a -> (a -> m b) -> m b
seems to suggest that the function, in my case the lambda function \x -> x, should return a different type to the one passed in. I would expect a compiler error in this case, but I don't have one. I'm running this in ghci.
Why doesn't the compiler throw an error in this case?
The identity function id :: a -> a, or explicitly \x -> x is polymorphic. This means it can be specialized to any type which you construct by substituting some type for a.
In your case (>>= id) the compiler looks at the type of the second argument of
(>>=) :: m c -> (c -> m d) -> m d
and at the type of id and tries to unify them:
a -> a -- id
c -> m d -- the second argument of >>=
this is satisfied in the most general way when we substitute a = m d and c = m d. So the most general type of id inside the expression(>>= id) is
id :: m d -> m d
and the type of the whole expression is
(>>= id) :: (Monad m) => m (m d) -> m d
which is the join function.
a, m and b are type variables and there is nothing that prevents a from being equal to m b in a given situation. That's the idea of polymorphism: if something has type a without any more constraints on a, then it also has type Int, and [[Bool]], and c -> [Int] -> d, and (like here) m b.
So for this specific call, a ~ [Int], b ~ Int, m ~ [], and therefore (>>=)'s type is [[Int]] -> ([Int] -> [Int]) -> [Int].
The inner list is seen as the outer list in the output, but a list is a list nevertheless.
The other way to say this is that
foreach x in [[1,2],[3,4]]:
foreach y in x:
emit y
and
foreach x in [1,2,3,4]:
emit x
are "the same" as regards the emitted elements.
I find the type presentations with lined-up subentities much visually appealing:
(>>=) :: m a -> (a -> m b) -> m b
[[1,2],[3,4]] :: [[Int]] -- actually, (Num a) => [[a]], but never mind that
\x -> x :: a -> a
(>>=) :: m a -> ( a -> m b) -> m b
(>>=) [[1,2],[3,4]] :: ( a -> m b) -> m b m a ~ [[Int]]
(>>=) [[1,2],[3,4]] :: ( a -> [b]) -> [b] m ~ []
(>>=) [[1,2],[3,4]] :: ([Int] -> [b]) -> [b] a ~ [Int]
(>>=) [[1,2],[3,4]] (\ x -> x ) :: [b] [b] ~ [Int]
(>>=) [[1,2],[3,4]] (\ x -> x ) :: [Int] b ~ Int
-- actually, (Num b) => b
Here, it turns out, \ x -> x :: (Num b) => [b] -> [b], not just a -> a.
You see, when ([Int] -> [b]) is matched with the type of (\ x -> x), creating the equivalence of [Int] ~ [b], the [] in [Int] comes from the "inner list", the a in m a; and the [] in [b] comes from the "outer list", the m in m b; but a list is a list, as was said above.
And that's what allows the two list levels to be smashed ("joined") into one — "flattening" a list, or more generally "joining" the two "levels" of a monad into one.
Another way to see it is to expand the monadic code with its specific list version:
[[1,2],[3,4]] >>= \x -> x
=== concatMap id [[1,2],[3,4]] === concat [ x | x <- [[1,2],[3,4]]]
=== concat [id [1,2], id [3,4]] === [ y | x <- [[1,2],[3,4]], y <- x]
=== [1,2,3,4] === [1,2,3,4]
All that matters for f in concatMap f is for it to be a list-producing function: f :: a -> [b].
And concatMap id === concat :: [[a]] -> [a] is a perfectly legal function. Yes, concat is join for the list monad:
ma >>= f === join (fmap f ma) -- or, for lists,
=== concat (map f ma)
=== concatMap f ma -- the definition that we used above
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
In ghci,
:t ((+).(+))
> ((+).(+)) :: (Num (a -> a), Num a) => a -> (a -> a) -> a -> a
but what is this thing? Can any one give me an example of the use of this please?
How can one composite 2 functions that take 2 parameters each?
for example, how does (map.map) :: (a -> b) -> [[a]] -> [[b]] work?
(^.^)
(-.-)
(+.+) (can't help making funny faces out of it. PS: I thought it means to tell the compiler how you feel today)
Num (a -> a) (or e.g. Eq (a -> a)) is basically an indicator for code that doesn't make any sense1, but the compiler nevertheless deduces a (nonsensical) type signature. Usually it turns up when you've forgotten to apply a function to some argument. In this case, obviously (+) needs a "plain number" argument to become a "simple function" to which you can post-compose another such function.
However, (a -> a) is sure enough a valid type of functions that you can also pass on, just not as numbers. For instance, map . (+) is a perfectly good combination:
Prelude> :t map . (+)
map . (+) :: Num b => b -> [b] -> [b]
Prelude> zipWith (map . (+)) [10,20,30] [[1,2],[3,4]]
[[11,12],[23,24]]
because map actually expects a function as its first argument. Similarly,
Prelude> zipWith (map . map) [(+10),(+20),(+30)] [[[1,2],[3,4]],[[5,6]]]
[[[11,12],[13,14]],[[25,26]]]
Here, the right map takes a simple function (like numerical increment) and returns the corresponding list-map function. That function is then fed to the left map resulting in a function that maps nested lists.
1Actually, you can force it to make sense by defining
instance (Num a) => Num (b -> a) where
fromInteger x = const $ fromInteger x
f + g = \x -> f x + g x
Personally, I'm not a fan of this. It confusing, for instance let a = 3 in 4 a produces 4 when most people would expect multiplication to 12.
That won't work. As ghci tells you, you should have an instance of Num (a -> a) in order to use that function, but a -> a obviously isn't a number.
This is because (+) assumes to get two numerical parameters, but with the composition you wrote you gave it a partially applied function instead, the a -> a mentioned in the computed type signature.
Usually, when composing functions which take more than one parameter, you partially apply them first in order to reduce them to functions which take just one parameter, e.g. (+1) . (*2) applied to 3 will result in (3 * 2) + 1 = 7
f . f can make sense for a binary function f; it entirely depends on the signature of f. The key is that partial application of the inner f to its first argument has to give something that is a valid input to the outer f.
For example, with map :: (a -> b) -> [a] -> [b], we can hand-unify map . map:
map :: (a -> b) -> [a] -> [b]
map :: (c -> d) -> [c] -> [d]
. :: (e -> f) -> (f -> g) -> (e -> g)
e === a -> b
f === [a] -> [b]
=== c -> d
c === [a]
d === [b]
g === [c] -> [d] === [[a]] -> [[b]]
map . map :: e -> g
:: (a -> b) -> [[a]] -> [[b]]
So, as expected, map . map takes a transformation a -> b and gives us a transformation from list-of-list-of-a to list-of-list-of-b. We can check this by hand-applying (map . map) f ll:
(map . map) f ll
= map (map f) ll
= map (\l -> map f l) ll
But if we try the same with (+) :: Num a => a -> a -> a, it all goes horribly wrong:
(+) :: Num a => a -> a -> a
(+) :: Num b => b -> b -> b
. :: (c -> d) -> (d -> e) -> (c -> e)
c === a
d === a -> a
=== b
e === b -> b === (a -> a) -> (a -> a)
(+) . (+) :: c -> e
:: (Num a, Num (a -> a)) => a -> (a -> a) -> (a -> a)
So, partial application of the inner + is giving a transformation a -> a, the outer + is then trying to add that transformation to another function which we are expected to supply. Since it doesn't make sense to add transformations, the overall (+) . (+) doesn't make sense either.
g . f means applying f first, then applying g to the result of f, in
other words, it can be rewritten as
\x -> g (f x)
Therefore,
((+) . (+))
can be rewritten as
\x -> (\y -> (x +) + y)
According to the type of (+), in the above lambda abstraction, x needs
having type Num a => a, y having type Num a => Num (a -> a), as inferred
by ghci
(Num a, Num (a -> a)) => a -> (a -> a) -> a -> a
So if we have made a -> a an instance of type class Num a, for example,
here is one way to achieve that
{-# LANGUAGE FlexibleInstances #-}
instance (Num a) => Num ((->) a a) where
a + b = \x -> a x + b x
a * b = \x -> a x * b x
a - b = \x -> a x - b x
negate a = \x -> negate $ a x
abs a = \x -> abs $ a x
signum a = \x -> signum $ a x
fromInteger n = \_x -> fromInteger n
we can use ((+) . (+)) like this
*Main> ((+) . (+)) 1 (+2) 3
9
Because ((+) . (+)) equals
\x -> \y -> (x +) + y
which means ((+) . (+)) 1 (+2) 3 equals
((1 + ) + (+ 2)) 3
according to the definition of (+) in the instance of (a -> a), ((1+) +
(+2)) equals
\x -> (1+x) + (x+2)
So ((1+) + (+2)) 3 equals (1+3) + (3+2), which is 9, as given by ghci.
map . map is similar, as indicated by its type, given by ghci:
(a -> b) -> [[a]] -> [[b]]
the first argument of that function should be a function of type a->b, the
second argument should be a nested list of type [[a]], and that composed
function map . map will apply the first argument to each element of each
list in its second argument, return a nested list of type [[b]]. For
example
*Main> (map . map) (+1) [[1,2], [3,4,5]]
[[2,3],[4,5,6]]