Why does (.) map have this type? - haskell

I tried to find the type of the function (.) map but somehow find that it is ((a -> d) -> (a -> e)) -> ([d] -> [e]) which according to GHCI is not correct because it should be (.) map :: (a1 -> a2 -> b) -> a1 -> [a2] -> [b].
What am I doing wrong?

Deriving the type...
We have as ingredients:
(.) :: (b -> c) -> (a -> b) -> a -> c
map :: (d -> e) -> [d] -> [e]
(here I used different type identifiers for the two functions to avoid any confusion). A more verbose form (where we make it more explicit that every function takes exactly one parameter) is:
(.) :: (b -> c) -> ((a -> b) -> (a -> c))
map :: (d -> e) -> ([d] -> [e])
Since map is the first parameter of (.) that means that its type (d -> e) -> ([d] -> [e]) should match the input type of the (.) function (so b -> c). This thus means:
b -> c
~ (d -> e) -> ([d] -> [e])
------------------------------
b ~ (d -> e), c ~ ([d] -> [e])
So that means that the result type of (.) map is:
(a -> b) -> (a -> c)
which is equivalent to:
(a -> (d -> e)) -> (a -> ([d] -> [e]))
or less verbose:
(.) map :: (a -> d -> e) -> a -> [d] -> [e]
... and its implementation
The (.) function can be seen as (.) f g == \x -> f (g x). So that means that our function
h = (.) map
is equivalent to:
h f x = map (f x)
It thus takes as input a function f and an object x, and than performs a map with f x as function.
Semancially you could say that we make a "map where one has to inject a 'contect'-objecct" of type a. This context is then taken into account by the processor. This could be useful if we want to apply multiple maps, each with a small change, and thus first pass a "context-object". This is of course an interpretation of humans. For a compiler, the x can have any use, interpretation, etc.

You have probably tried to match the functions by looking at the definition
Types of the two functions
(.) :: ((b -> c) -> (a -> b) -> a -> c)
map :: (d -> e) -> [d] -> [e]
and then trying to match d to b and e to c. Which gives you ((a -> d) -> (a -> e)) -> ([d] -> [e]), now you could match [d] to a and [e] to d. This is however not correct because according to the type definition of map, e and d could be of different type, i.e. d could be of type [e] but it doesn't have to.
The correct way to find the type of this function is to look at the definition of the types
Types of the two functions
(.) :: ((b -> c) -> (a -> b) -> a -> c)
map :: (d -> e) -> [d] -> [e]
and then to match (d -> e) to b and [d] -> [e] to c which gives you (a -> (d -> e)) -> a -> ([d] -> [e]), by removing the superfluous brackets and renaming the type variables you get (a -> b -> c) -> a -> [b] -> [c]. This is the same result GHCI gives you.

When I don't understand the type of a function, I write types using different letters:
(.) :: (b -> c) -> (a -> b) -> a -> c
map :: (x -> y) -> [x] -> [y]
now we are providing map as the first argument of (.) so we can deduce:
b -> c == (x -> y) -> [x] -> [y] -- by matching first arguments we get...
b == x -> y
c == [x] -> [y]
since we have already provided the first argument of (.), the whole b -> c part disappears.
(.) map :: (a -> b) -> a -> c -- Using the above equations for b and c
(.) map :: (a -> x -> y) -> a -> [x] -> [y] -- changing variables names
(.) map :: (a1 -> a2 -> b) -> a1 -> [a2] -> [b]
as GHCi plots

Related

Calculating the type of `map . foldr`

map :: (a -> b) -> [a] -> [b]
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
What is a systematic way to figure out the type for map . foldr ? I know how to do it for map foldr but get confused when it comes to a composition.
Thanks!
Obviously there must be a systematic way, otherwise the Haskell compiler could not do type inference.
One way we can do this ourselves is insert the types step by step:
We have the following types:
(.) :: (b -> c) -> (a -> b) -> (a -> c)
map :: (a' -> b') -> [a'] -> [b']
foldr :: Foldable t => (a'' -> b'' -> b'') -> b'' -> t a'' -> b''
Note that you have to choose different names for types appearing in different signatures for this to work out.
1. supply map to (.)
If we supply a generic function f to (.) we get the following types:
(.) :: (b -> c) -> (a -> b) -> (a -> c)
(.) f :: (a -> b) -> (a -> c)
f :: (b -> c)
choose f to be map:
map :: (a' -> b') -> [a'] -> [b']
equal to
map :: (a' -> b') -> ([a'] -> [b'])
as f has type (b -> c) we can conclude:
b :: (a' -> b')
c :: ([a'] -> [b'])
insert our inferred types:
(.) f :: (a -> b) -> (a -> c)
(.) map :: (a -> (a' -> b')) -> (a -> ([a'] -> [b']))
we can drop some parentheses:
(.) map :: (a -> (a' -> b')) -> a -> ([a'] -> [b'])
(.) map :: (a -> (a' -> b')) -> a -> [a'] -> [b']
(.) map :: (a -> a' -> b') -> a -> [a'] -> [b']
2. supply foldr to (.) map
Again start by suppling a generic function g:
(.) map :: (a -> a' -> b') -> a -> [a'] -> [b']
(.) map g :: a -> [a'] -> [b']
g :: (a -> a' -> b')
choose g to be foldr:
foldr :: Foldable t => (a'' -> b'' -> b'') -> b'' -> t a'' -> b''
equal to
foldr :: Foldable t => (a'' -> b'' -> b'') -> b'' -> (t a'' -> b'')
as g has type (a -> a' -> b') we can conclude:
a :: (a'' -> b'' -> b'')
a' :: b''
b' :: Foldable t => t a'' -> b''
insert our inferred types:
(.) map foldr :: a -> [a'] -> [b']
(.) map foldr :: Foldable t => (a'' -> b'' -> b'') -> [b''] -> [t a'' -> b'']
Which is the same type we get, when asking ghci for the type:
> :t ((.) map foldr)
((.) map foldr) :: Foldable t => (a1 -> a2 -> a2) -> [a2] -> [t a1 -> a2]
map . foldr is actually (.) map foldr. Adding the type of (.) into the mix we get
foldr :: Foldable t => (a -> (r->r)) -> (r -> (t a -> r))
map :: (i -> j) -> ([i] -> [j])
(.) :: ( b -> c ) -> ( d -> b ) -> (d -> c)
-----------------------------------------------------------------------------------------
-- 4 2 1 3
-----------------------------------------------------------------------------------------
(.) map foldr :: Foldable t => (d -> c)
where d ~ a -> (r -> r) -- 1
c ~ [i] -> [j] -- 2
b ~ r -> (t a -> r) -- 3
~ i -> j -- 4
-------------------
i ~ r -- 5
j ~ t a -> r -- 6
thus
map . foldr :: Foldable t => a -> (r -> r) -> [i] -> [j] -- by 1,2
~ Foldable t => a -> (r -> r) -> [r] -> [t a -> r] -- by 5,6
Here we used the application type derivation rule,
f :: A -> B
x :: A
---------------
f x :: B
(otherwise known as modus ponens, in logic).
We could also use a composition type derivation rule which is the application rule specialized for (.), or equivalently (>>>) = flip (.):
g :: B -> C
f :: A -> B
------------------------
f >>> g :: A -> C
g . f :: A -> C
To fit this pattern, we write the types down a bit differently, and obtain the result immediately:
map :: (i -> j ) -> ([i] -> [ j ])
foldr :: Foldable t => (a -> (r->r)) -> (r -> (t a -> r))
------------------------------------------------------------------------------------
foldr >>> map :: Foldable t => (a -> (r->r)) -> [r] -> [t a -> r]
map . foldr :: Foldable t => (a -> (r->r)) -> [r] -> [t a -> r]
It is much more intuitive this way.
Ok, rather than using an automatic method to infer the type I thought maybe you’ll be interested in a more intuitive answer:
As I’m sure you know, map . foldr is equivalent to (\x -> map (foldr x)). Let’s start with that.
What should be the type of x ? Well, since it’s the first parameter to foldr, it should look like a function that takes some value, some accumulator, and return something of the same type as the accumulator (by definition of foldr). Thus :
x :: (a -> b -> b)
Now that we have the type of the first parameter, let’s look at the rest.
Once (foldr x) is applied, we get back a function that stills waits for an initial accumulator value, and then for any foldable type, and returns a value of the same type as the accumulator (for example, the sum of every element in a list).
So the type of (foldr x) should be
Foldable t => b -> t a -> b
Ok but we're not done, let’s see what happens with the use of map now.
map should first be given a function (by definition). The return value of (foldr x) is seen as that, which means that this use of map considers that (b -> t a -> b) is the type of the function that needs to be applied to every element of a list.
Maybe it’s clearer written as (b -> (t a -> b)). So, this use of map considers that it is given a function that takes some input of type b and returns a function that itself takes a foldable a and returns a b.
Ok we’re almost there. Now, map still needs another argument: a list which elements are of the same type as the input of the function it will apply. So since the function we want to apply (the result of (foldr x)) takes a b, our use of map will take a [b].
So now we have :
(a -> b -> b) -> [b] -> …
We’re just lacking the type of the output value of that function composition, which is the type of the output value of this specific use of map. Since the function that is applied with map returns something of type (t a -> b), then the list of thing we will obviously return will be of type [t a -> b].
So in the end you have
Foldable t => (a -> b -> b) -> [b] -> [t a -> b]
as the type of map . foldr.

The type of foldr (.) id

I'm trying to figure out the type of the expression :
foldr (.) id
GHCI gives me :
foldr (.) id :: Foldable t => t (b -> b) -> b -> b
And I can't figure this out. foldr type is Foldable t => (a -> b -> b) -> b -> t a -> b.
So it takes 3 parameters as input. So i thought that foldr (.) id should take a single parameter as input. Can someone explain how to analyze the type of this expresion ?
The type Foldable t => t (b -> b) -> b -> b reads as:
(Foldable t => ...) Choose any list-like "container" type t,
(t (b -> b) -> ... ) then provide as an argument a t-container of functions b -> b,
(b -> b) the final result will be a function b -> b.
So, it's only slightly more general than: "give me a list of functions, and I will produce a function".
Indeed, when we use lists as containers:
foldr (.) id [f1,f2,f3,...,fn]
results, by definition of foldr, in
f1 . (f2 . (f3 . ... (fn . id) ...))
which is the composition of all the functions in the list.
So i thought that foldr (.) id should take a single parameter as input.
It does: the argument has type t (b -> b). Every function in Haskell takes a single parameter as input. E.g.
foo :: T -> U -> W -> Z
takes T and returns a function U -> W -> Z.
Now, we can also say that foo takes two arguments of type T and U and returns a function W -> Z. Or That it takes three arguments T, U, and W, and returns a Z. There is no real difference between these interpretations of a type, thanks to currying, so we can pick the one which is the easiest to grasp.
In your case, the result type of foldr (.) id is b -> b, so one usually interprets the first b as an additional argument. This does not provide a good intuition, though. It's easier to think of b -> b being the result type.
More technically: the type of foldr is (renaming variables for clarity).
foldr :: Foldable t => (a -> c -> c) -> c -> t a -> c
In foldr (.) id, we can see that the type of the second argument is id :: b -> b, hence we are using c = (b -> b), as if we specialized the above type to:
foldr :: Foldable t => (a -> (b -> b) -> (b -> b)) -> (b -> b) -> t a -> (b -> b)
Now, the first argument must have type (.) :: (a -> (b -> b) -> (b -> b)) to type check. This is possible only if a = (b -> b). Hence, we specialize again.
foldr :: Foldable t =>
((b -> b) -> (b -> b) -> (b -> b)) ->
(b -> b) ->
t (b -> b) ->
(b -> b)
which is the final type: after this specialization, foldr can then be applied to (.) and id.
All the specializations above are inferred automatically by GHC from your code. Essentially, GHC chooses a and c in the only way that can make your code type check
TLDR answer:
foldr (.) id :: Foldable t => t (b -> b) -> b -> b
DOES take one argument. It takes a t (b -> b) and returns a b -> b.
This confusion is usually due to Haskell allowing the omission of parens in type signatures. Parens in types associate to the right. So another way to look at this:
foldr :: Foldable t => (a -> r -> r) -> (r -> (t a -> r))
(.) :: (c -> d) -> (b -> c) -> (b -> d)
-- a -> r -> r
(.) :: (c -> c) -> (b -> c) -> (b -> c)
foldr (.) :: Foldable t => (b -> c) -> (t (c -> c) -> (b -> c))
id :: b -> b
foldr (.) id :: Foldable t => t (b -> b) -> (b -> b)
You could
resultFun = foldr (.) id [(+1), (*4)]
resultFun 5
>>> 21
Or even
foldr (.) id [(+1), (*4)] 5
>>> 21

What is the type of foldr map in haskell?

I am trying to find out what the type of foldr map is, and how you should be solving something like this.
I know what the individual types are:
foldr :: (a -> b -> b) -> b -> [a] -> b
map :: (a -> b) -> [a] -> [b]
I know how the individual functions work, but finding out the type is something I just can't seem to solve.
foldr would take a function as first parameter, which would be the whole of map right?
All tips are welcome, I am new to Haskell and trying to learn puzzles like these.
As ingredients we have foldr and map. To avoid confusion, let us rename the a and b of map to c and d, since those are (possibly) different types. So we take as functions:
foldr :: (a -> b -> b) -> b -> [a] -> b
map :: (c -> d) -> [c] -> [d]
or more verbose:
foldr :: (a -> (b -> b)) -> (b -> ([a] -> b))
map :: (c -> d) -> ([c] -> [d])
Since map is the parameter of a function application with foldr as function, this means that the type of map should be the same as the type of the parameter of foldr, hence:
a -> (b -> b)
~ (c -> d) -> ([c] -> [d])
----------------------------------
a ~ (c -> d), b ~ [c] ~ [d], c ~ d
So we have derived that a is the same type as c -> d, and that b is the same type as [c] and [d]. Therefore we also know that c ~ d (c is the same type as d).
The type of foldr map is the return type of the foldr function, but specialized with the equality relations we have derived, so:
foldr map :: b -> ([a] -> b)
so we replace a with c -> c, and b with [c], hence the type:
foldr map :: [c] -> ([c -> c] -> [c])
or in a less verbose form:
foldr map :: [c] -> [c -> c] -> [c]
Note: the signature of foldr has been generalized to foldr :: Foldable f => (a -> b -> b) -> b -> f a -> b, but deriving the type is similar.

Calculating type Haskell

How to calculate type of (.)(.) in Haskell?
I know that it should be
(.)(.) :: (a -> b -> c) -> a -> (a1 -> b) -> a1 -> c
But how to calculate it without computer?
(.) :: (b -> c ) -> ((a -> b) -> (a -> c))
(.) :: ((e -> f) -> ((d -> e) -> (d -> f)))
(.)(.) :: ((a -> (e -> f)) -> (a -> ((d -> e) -> (d -> f))))
(.)(.) :: (a -> (e -> f)) -> (a -> ((d -> e) -> (d -> f)))
(.)(.) :: (a -> e -> f) -> a -> ((d -> e) -> (d -> f))
(.)(.) :: (a -> e -> f) -> a -> (d -> e) -> (d -> f)
(.)(.) :: (a -> e -> f) -> a -> (d -> e) -> d -> f
by (manual) pattern-matching and rewriting types-variables
(.) has type (b -> c) -> ((a -> b) -> a -> c) so the first argument should have type b -> c.
Now if we use it again we have to substitute b with b' -> c' and c with (a' -> b') -> a' -> c') (the second (.) should have type (b' -> c') -> ((a' -> b') -> a' -> c')) and we get
(a -> b' -> c') -> a -> (a' -> b') -> a' -> c'
which is (after renaming) the same as above.
Note that I used a -> b -> c = a -> (b -> c) here
using GHCi
yeah I know - you want it by hand - but GHCi is such a valuable tool that you really should use it to confirm your manual labor.
Here from a terminal:
$ ghci
GHCi, version 7.10.1: http://www.haskell.org/ghc/ :? for help
Prelude> :t (.)(.)
(.)(.) :: (a -> b -> c) -> a -> (a1 -> b) -> a1 -> c
Prelude>
as you can see the type is (a -> b -> c) -> a -> (a1 -> b) -> a1 -> c
btw: :t is short for :type and you can see all commands with :help from inside a GHCi session.
Since I wasn't particularly satisfied with the missing explanations in the accepted answer, I give my POV as well:
-- this is the original type signature
(.) :: (b -> c) -> (a -> b) -> a -> c
-- now because of haskell polymorphism,
-- even 'b' and 'c' and so on could be functions
--
-- (.)(.) means we shove the second function composition
-- into the first as an argument.
-- Let's give the second function a distinct type signature, so we
-- don't mix up the types:
(.) :: (e -> f) -> (d -> e) -> d -> f
-- Since the first argument of the initial (.) is of type (b -> c)
-- we could say the following if we apply the second (.) to it:
(b -> c) == (e -> f) -> (d -> e) -> d -> f
-- further, because of how currying works, as in
(e -> f) -> (d -> e) -> d -> f == (e -> f) -> ((d -> e) -> d -> f)
-- we can conclude
b == (e -> f)
c == (d -> e) -> d -> f
-- since we passed one argument in, the function arity changes,
-- so we'd actually only have (a -> b) -> a -> c left, but that
-- doesn't represent the types we have now, so we have to substitute
-- for b and c, so
(a -> b) -> a -> c
-- becomes
(.)(.) :: (a -> (e -> f)) -> a -> (d -> e) -> d -> f
-- and again because of currying we can also write
(.)(.) :: (a -> e -> f) -> a -> (d -> e) -> d -> f

function composition type inference in haskell

In haskell, the type of (.) function is:
(.) :: (b -> c) -> (a -> b) -> a -> c
And the type of (.) (.) is:
(.) (.) :: (a -> b -> c) -> a -> (a1 -> b) -> a1 -> c
I am not able to deduce the result, how is this done?
(.) :: (b -> c) -> (a -> b) -> a -> c
Let's go through it. First thing this function takes is (b -> c) (so a function from b to c), cool. By adding a pair of (redundant) parentheses:
(.) :: (b -> c) -> ((a -> b) -> a -> c)
^-- I am b' ^-- I am c' -- (b' and c' not to have name clash)
That first part, we gave to the function (i.e. has been taken care of):
(.) (.) :: (a -> b') -> a -> c'
-- after substituting stuff (b' and c')
(.) (.) :: (a -> (b -> c)) -> a -> ((a1 -> b) -> a1 -> c)
^-- of course a1 /= a
-- you could eliminate redundant parentheses
(.) (.) :: (a -> b -> c) -> a -> (a1 -> b) -> a1 -> c
-- wee
I hope this settles it. Main point is: type inference is easy to 'get' and once you get it is only a matter of substitution to reach what ghci automagically infers.
ot: we could call this quizzical operator boobs.

Resources