Function gets four arguments instead of three - why doesn't this break? - haskell

Reading "Real World Haskell", on page 95 the author provides an example:
myFoldl f z xs = foldr step id xs z
where step x g a = g (f a x)
My question is: Why does this code compile? foldr takes only three arguments - but here, it is passed four: step, id, xs, z.
For example, this doesn't work (because sum expects one):
sum filter odd [1,2,3]
instead I must write:
sum $ filter odd [1,2,3]

Here's the type of foldr:
Prelude> :t foldr
foldr :: (a -> b -> b) -> b -> [a] -> b
Can we figure out how it becomes a four-argument function? Let's give it a try!
we're giving it id :: d -> d as the second parameter (b), so let's substitute that into the type:
(a -> (d -> d) -> (d -> d)) -> (d -> d) -> [a] -> (d -> d)
in Haskell, a -> a -> a is the same as a -> (a -> a), which gives us (removing the last set of parentheses):
(a -> (d -> d) -> (d -> d)) -> (d -> d) -> [a] -> d -> d
let's simplify, by substituting e for (a -> (d -> d) -> (d -> d)) and f for (d -> d), to make it easier to read:
e -> f -> [a] -> d -> d
So we can plainly see that we've constructed a four-argument function! My head hurts.
Here's a simpler example of creating an n + 1-argument function from an n-arg func:
Prelude> :t id
id :: a -> a
id is a function of one argument.
Prelude> id id id id id 5
5
But I just gave it 5 args!

It's because of how polymorphic foldr is:
foldr :: (a -> b -> b) -> b -> [a] -> b
Here, we've instantiated b to a function type, let's call it c -> c, so the type of foldr specializes to (for example)
foldr :: (a -> (c -> c) -> (c -> c)) -> (c -> c) -> [a] -> c -> c

foldr only takes 3 arguments
Wrong. All functions in Haskell take exactly 1 argument, and produce exactly 1 result.
foldr :: (a -> b -> b) -> b -> [a] -> b
See, foldr takes one argument (a -> b -> b), and produces 1 result: b -> [a] -> b. When you see this:
foldr step id xs z
Remember, it is just shorthand for this:
((((foldr step) id) xs) z)
This explains why this is nonsense:
sum filter odd [1,2,3]
(((sum filter) odd) [1,2,3])
sum :: Num a => [a] -> a takes a list as its input, but you gave it a function.

Related

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.

How does the second parameter become a list of functions?

I am playing a bit with zipWith and encounter following:
Prelude Control.Applicative> :t zipWith id
zipWith id :: [b -> c] -> [b] -> [c]
Why does the compiler expect for the next argument a list of functions?
I tried to analyze, but could not conclude, why the next argument must be a list of functions.
How did the signature is getting apply, when I pass id to zipWith?
The type of zipWith is:
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
And the type of id is:
id :: d -> d
So if we now want to derive the type of zipWith id, we push the type of id :: d -> d into the type of the first argument of zipWith:
d -> d
~ a -> (b -> c)
So that means that: a ~ d and a ~ b -> c. So that means that the type of zipWith id is now:
zipWith id :: [a] -> [b] -> [c]
-> zipWith id :: [b -> c] -> [b] -> [c]
How does this work: the first list has to contain a list of functions f :: b -> c, and the second list, a list of elements x :: b, and it thus calculates a list of elements f x :: c.
For example:
Prelude> zipWith id [(+1),(5/),(3*),(3-)] [1,4,2,5]
[2.0,1.25,6.0,-2.0]
since 1+1 is 2.0, 5/4 is 1.25, 3*2 is 6.0 and 3-5 is -2.0.
So zipWith id will take two elements f and x, and apply id f x on these, or more verbose (id f) x. Since id f is f, it will thus calculate f x.
We can thus conclude that zipWith is an elementwise mapping.
Thank you, Willem Van Onsem for the great answer.
Let's understand zipWith id from the eyes of the type inference system of ghc.
first, consider the type of zipWith
Prelude> :info zipWith
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
-- Defined in ‘GHC.List’
First argument of zipWith is a function which accepts a function which takes two arguments.
(a -> b -> c) can also be re-written as a -> (b -> c)
now consider zipWith id. type of id is from a -> a
we have put id in a place where a two argument function must go.
So, type inference would make (a -> b -> c) look like a -> (b -> c) (notice a -> (b -> c) takes one arument a and gives b -> c i.e a single argument function.)
But, making a -> (b -> c) an identity function would be possible only if a is (b -> c).
When a is (b -> c) the function a -> b -> c becomes ((b -> c) -> (b -> c))
So, type inferencing system would infer a as (b -> c) and the resultant output would be [a] -> [b] -> [c] replacing a with b -> c.
Replace a with (b -> c).
Make (a -> b -> c) look like id. (a -> b -> c) can be made to look like id by the above replacement.
((b -> c) -> b -> c) which can also be written as ((b -> c) -> (b -> c)) which is id :: x -> x where x is (b -> c)
zipWith :: ((b -> c) -> b -> c) -> [b -> c] -> [b] -> [c]
So finally we get output as [b -> c] -> [b] -> [c]

How do you define and use curry and uncurry (Prelude functions) in Haskell?

How can I use curry and uncurry prelude functions in Haskell?
Moreover, why do the following definitions throw an error when loaded?
curry' :: ((a -> b) -> c) -> a -> b -> c
curry' f = \x y -> f (x, y)
uncurry' :: a -> b -> c -> ((a -> b) -> c)
uncurry' f = \(x,y) -> f x y
You're getting errors because your type signatures are wrong, you should be using tuples instead of functions for the a and b arguments:
curry' :: ((a, b) -> c) -> a -> b -> c
uncurry' :: (a -> b -> c) -> ((a, b) -> c)
Also, notice the parentheses I added to uncurry's type, those are important in this case. What you have is equivalent to
uncurry' :: a -> (b -> (c -> ((a -> b) -> c)))
Which is not the same, this is a function that takes 3 arguments and produces a function instead of a function that takes a 2 argument function and returns a function of one tuple argument.
You could use these functions like
> uncurry (+) (1, 2)
3
> curry fst 1 2
1
> curry snd 1 2
2
(I didn't see any other Prelude functions that take tuples as arguments)
EDIT: At chi's request, here's a more visual explanation of that last sentence:
a -> (b -> (c -> ((a, b) -> c)))
is the type of a function that takes 3 arguments a, b, and c, and returns a function of type (a, b) -> c.
(a -> b -> c) -> ((a, b) -> c)
is the type of a function that takes a single argument a -> b -> c and returns a function (a, b) -> c.

map . foldr function composition - Haskell

So, let's straight to the point.
:t (map.foldr)
(map.foldr) :: (a1 -> a -> a) -> [a] -> [[a1] -> a]
What is [[a1] -> a]?
I'm really trying to understand this composition, so I was doing this:
-- map.foldr
map.foldr :: (a1 -> a -> a) -> [a] -> [[a1] -> a]
map :: (a1 -> b1) -> [a1] -> [b1]
(.) :: (y -> w) -> (x -> y) -> x -> w
foldr :: (a -> b -> b) -> b -> [a] -> b
y = (a1 -> b1) w = ([a1] -> [b1])
x = (a -> b -> b) y = (b -> [a] -> b)
y = (a1 -> b1)
y = (b -> [a] -> b)
_________________________
What happens in this point? Thank you!
To answer this question it's good to recall what foldr and map do.
The more complicated of the two is foldr, which has type
-- list to be folded
-- v
foldr :: (a -> b -> b) -> b -> [a] -> b
-- ^ ^
--folding function terminal value
The list to be folded is really a chain of conses (:) and a terminal empty list:
1 : 2 : 3 : []
The action of foldr is to replace the : and [] constructors with the folding function and the terminal value, respectively:
foldr (+) 0 (1 : 2 : 3 : []) == 1 + 2 + 3 + 0
The map function is simpler. One way of thinking of it is as taking a function and a list, and applying the function to every argument of the list:
map :: (a -> b) -> [a] -> [b]
-- ^ ^
-- function list
However, you can also think of it as taking a function, and lifting it to be a function that acts on lists instead:
map :: (a -> b) -> ( [a] -> [b] )
-- ^ ^
-- function function on lists
What does it mean to compose these two functions, map . foldr? Note that this is just applying the functions one after the other - in particular,
(map . foldr) f == map (foldr f)
Since you apply foldr first, you must be applying it to a function f :: a -> b -> b, and you get back another function:
foldr f :: b -> [a] -> b
-- ^ ^
--terminal val list to be folded
Now you apply map, which lifts the function to act on lists:
map (foldr f) :: [b] -> [[a] -> b]
-- ^ ^
--list of terminal vals functions that fold lists
This type looks odd, but it's valid. Now instead of a single terminal value, you give it a list of terminal values, and you get a list of folding functions back - one for each terminal value that you supplied.
To make it clearer we could look at a particular function, (+), which has type
(+) :: Num a => a -> a -> a
If we substitute that into the equation above, we get
(map . foldr) (+) :: Num a => [a] -> [[a] -> a]
-- ^ ^
-- list of terminal vals functions that fold lists
If we now apply it to the list [0, 1, 2] we get a list of three functions:
(map . foldr) (+) [0,1,2] :: Num a => [[a] -> a]
We can use the map ($x) idiom to apply each of the functions in the list to a particular argument. It has to be a list of numbers, and I'll choose [3,4,5]. Watch carefully:
> map ($[3,4,5]) ((map.foldr) (+) [0,1,2])
[12, 13, 14]
The list [3,4,5] was folded three times using (+) as the folding function, and each time with a different terminal value:
3 + 4 + 5 + 0 == 12
3 + 4 + 5 + 1 == 13
3 + 4 + 5 + 2 == 14
When the terminal value is 0, we simply get the sum of the values: 3 + 4 + 5 == 12. When the terminal value is 1 we get one more than the sum of the values (13) and when the terminal value is 2 we get two more than the sum of the values (14).
To continue where you left off, the two definitions of y must be equal:
y = (a1 -> b1) = (b -> [a] -> b)
= (b -> ([a] -> b))
so we can conclude that:
a1 = b
b1 = [a] -> b
The function composition has been supplied two function arguments, so the resulting type is just:
x -> w
But we know:
x = a -> b -> b
w = [a1] -> [b1] = [b] -> [[a] -> b]
So, the result type is:
(x -> w) = ((a -> b -> b) -> ([b] -> [[a] -> b]))
= (a -> b -> b) -> [b] -> [[a] -> b]
which is congruent to:
(a1 -> a -> a) -> [a] -> [[a1] -> a]
map.foldr :: (a1 -> a -> a) -> [a] -> [[a1] -> a]
map :: (a1 -> b1) -> [a1] -> [b1]
(.) :: (y -> w) -> (x -> y) -> x -> w
foldr :: (a -> b -> b) -> b -> [a] -> b
-- if you substitute: x = (a -> b -> b) y = (b -> [a] -> b)
-- then you get for map :: (b -> ([a] -> b)) -> [b] -> [[a] -> b]
-- so if composition operator applied:
map . foldr :: (a -> b -> b) -> [b] -> [[a] -> b]

Resources