What is the justification for the type of unfoldr in Haskell? - haskell

The example given in the documentation of unfoldr :: (b -> Maybe (a, b)) -> b -> [a]:
unfoldr (\b -> if b == 0 then Nothing else Just (b, b-1)) 10
can easily be written with a redundant pair:
unfoldr (\b -> if b == 1 then Nothing else Just (b-1, b-1)) 11
What does unfoldr need the pair (a,b) for? Why is its type not (a -> Maybe a) -> a -> [a]?

A function with type
(a -> Maybe a) -> a -> [a]
restricts the output list element type to be the same as the state which is threaded through the generation process. unfoldr is more general in that it allows an independent type of state to be used.

Leveraging a bit of theory, one can recover the types for folds/unfolds of a recursive type, including lists, understanding why they are what they are.
Let A be a fixed type. The type "list of As" satisfies the isomorphism
List ~~ Either () (A, List)
which can be read "a list value is either a special value (the empty list), or a value of type A followed by a list value".
In a more succinct notation we could write Either as an infix +:
List ~~ () + (A, List)
Now, if we let F b = () + (A, b), we have that
List ~~ F List
The above is a fixed point equation, which always arises when using recursive types. For any recursive type defined by T ~~ F T we can
derive the type of the related folds/unfolds (also known as cata/ana or induction/coinduction principles)
fold :: (F b -> b) -> T -> b
unfold :: (b -> F b) -> b -> T
In the case of lists, we then obtain
fold :: ((() + (A, b)) -> b) -> List -> b
unfoldr :: (b -> (() + (A, b))) -> b -> List
The unfold can also be rewritten noting that Maybe c ~~ () + c:
unfoldr :: (b -> Maybe (A, b)) -> b -> List
The fold can instead be rewritten using
((x + y) -> z) ~~ (x -> z, y -> z)
getting
foldr :: (() -> b, (A, b) -> b) -> List -> b
then, since () -> b ~~ b,
foldr :: (b, (A, b) -> b) -> List -> b
finally, since (x, y) -> z ~~ x -> y -> z (currying), we have
foldr :: b -> ((A, b) -> b) -> List -> b
and again:
foldr :: b -> (A -> b -> b) -> List -> b
and with a final flip x -> y -> z ~~ y -> x -> z:
foldr :: (A -> b -> b) -> b -> List -> b
How do those types follow from the (co)induction principles?
Domain theory states that least fixed points (F(T)=T) coincide with least
prefixed points (F(T)<=T), when F is monotonic over a certain poset.
The induction principle simple states that, if T is the least prefixed point, and F(U)<=U, then T<=U. (Proof. It is the least!. QED.)
In formulae,
(F(U) <= U) ==> (T <= U)
To deal with fixed points over types, we need to switch from posets to categories, which makes everything more complex. Very, very roughly, every <= is replaced with some morphism. For instance, F(U)<=U now means that there is some morphism F U -> U. "Monotonic F" means that F is a functor (since a<=b implying F(a)<=F(b) now becomes (a->b) implying F a -> F b). Prefixed points are F-algebras (F u -> u). "Least" becomes "initial". And so on.
Hence the type of fold: (implication is -> as well)
fold :: (F u -> u) -> (T -> u)
Unfold derives from the coinduction principle, which deals with greatest postfix points T (which become coalgebras)
(U <= F(U)) ==> (U <= T)

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

Top-down recursion schemes

Can we define a recursion scheme (without losing any of their generality) that constructs the value top-down, instead of bottom-up?
This would be quite helpful as I've seen plenty of times where the function, defined internally with a recursion scheme was first applying reverse to its input, clearly signalling the need for a foldl-like "front to back" execution.
Although it's a common belief that cata works "bottom-up", it can actually express many "top-down" constructions, by instantiating the carrier with a function whose parameter is the information being passed "top-down":
cata :: (F c -> c ) -> Fix F -> c -- general signature
:: (F (i -> d) -> (i -> d)) -> Fix F -> i -> d -- with c = (i -> d)
That's how you can implement foldl or reverse using foldr (which is cata for lists).
-- foldl :: (b -> a -> b) -> b -> [a] -> b
-- using
-- foldr :: (a -> (b -> b) -> (b -> b)) -> (b -> b) -> [a] -> b -> b
foldl f b xs = foldr (\x go z -> go (f z x)) id xs b
Here's another example to label a tree by depth, counting from the root:
data Tree a = Node (Tree a) a (Tree a) | Leaf
makeBaseFunctor ''Tree -- recursion-schemes
byDepth :: Tree a -> Tree Integer
byDepth t = cata byDepthF t 0 where
byDepthF :: TreeF a (Integer -> Tree Integer) -> Integer -> Tree Integer
byDepthF (NodeF u _ v) !d = Node (u (d + 1)) d (v (d + 1))
byDepthF LeafF = Leaf

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.

Haskell: Evaluating lambda expressions manually - determine general types

First of all, sorry if I'm not not posting this on the correct site since I'm not sure if it's more of a mathematical question than a programming one, but since I'm using this with Haskell and comparing the results with a Haskell interpreter, I just thought I'd ask it here.
So I'm basically trying to evaluate lambda expressions in Haskell and I'm doing it manually (in preparation for an exam, since I'll be forced to do it on paper). I'm given some expressions and I have to write down their general types after they're evaluated. To do so, I'm using an interpreter to get a somewhat correct answer.
In particular, I'm going to evaluate the following expressions:
t2 = ( \x y z -> y.x.y );
tx2 = (\x y z -> y.z.z);
tp2 = (\x -> \y -> (x.y.x));
td2 = (\x y z f -> y(z(z(f))));
tm2 = (\z -> \y -> \x -> z.y.x);
Since I don't 100% understand how to do this, I've devised a method. First, I create a template that somewhat resembles what the evaluated expression will look like. I.E. if part of the left-size ('lambda'd') variable is featured on the right side (as it's pretty much functional composition in every case), it's a function. If not, it's just a variable. Afterwards, I'm trying to fit the general types of the functions as best as I can and I'm getting some semi-right results, but I'm sure I'm still making some mistakes. Here's my whole evaluation process:
t2 = ( \x y z -> y.x.y );
(_ -> _) -> (_ -> _) -> c -> _ -> _
y(x(y))
assume:
y :: a -> b
x :: b -> a
result: (b -> a) -> (a -> b) -> c -> a -> b
interpreter: (a -> b) -> (b -> a) -> c -> b -> a
z isn't featured on the right side, so it's not a function in this case. I'm assigning it c. Now I'm looking at the composition on the right side. I'm going right to left and I assign a -> b to y since I have no idea about it's input or output. Since x uses the result of y as an input, and y uses x' output as an input again, x is b -> a. Which I can just insert into my template.
As you can see, it's not exactly the same result as I get via the interpreter, but it's only a and b being switched around, so it doesn't seem that wrong.
tx2 = (\x y z -> y.z.z);
a -> (_ -> _) -> (_ -> _) -> _ -> _
y(z(z))
assume:
z :: b -> b
y :: b -> c
result: a -> (b -> c) -> (b -> b) -> b -> c
interpreter: a -> (b -> c) -> (b -> b) -> b -> c
Same as above. Since z uses itself in functional composition, I assume it has the same input and output. y uses z's output as input and has some unknown output, hence c. This appears to be in line with my interpreter.
tp2 = (\x -> \y -> (x.y.x));
(_ -> _) -> (_ -> _) -> _ -> _
x(y(x))
assume:
x :: a -> b
y :: b -> a
result: (a -> b) -> (b -> a) -> a -> b
interpreter: (a -> b) -> (b -> a) -> a -> b
Pretty much the same as the first example, only I don't have an unused lambda variable.
td2 = (\x y z f -> y(z(z(f))));
a -> (_ -> _) -> (_ -> _) -> (_ -> _) -> _ -> _
y(z(z(f)))
assume:
f :: _ -> b
z :: b -> b
y :: b -> c
assume: a -> (b -> c) -> (b -> b) -> (_ -> b) -> b -> c
result: a -> (b -> c) -> (b -> b) -> (b -> b) -> b -> c
interpreter: a -> (b -> c) -> (b -> b) -> b -> c
Everything but x is a function in this case. f's Input isn't initially known to me and I'm just leaving it empty at the time. z uses f's output and it's own output in composition, so I just assign it b -> b. y uses z's output, and has an unknown output itself, so it gets b -> c.
Now I insert it into my template, but I'm still missing an input for f. Since there's a b right after f, I just assume it uses b as an input, too.
Now there's the first real question: where did f disappear to in the answer given by the interpreter? I can only assume since it uses the same input/output as z and it's basically in composition with it, it just got simplified into a single b->b, but I'm not sure about this.
tm2 = (\z -> \y -> \x -> z.y.x);
tm2 = (\z y x -> z.y.x);
(_ -> _) -> (_ -> _) -> (_ -> _) -> _ -> _
z(y(x))
assume:
x = a -> b
y = b -> _
z = _ -> _
assume: (_ -> _) -> (b -> _) -> (a -> b) -> _ -> _
result?: (a -> c) -> (b -> a) -> (a -> b) -> a -> c
interpreter: (a -> b) -> (c -> a) -> (d -> c) -> d -> b
Here's where it all falls apart: z, y, and x are functions. So I'm just assigning a -> b to x, which means that y's input is b. The output is unknown to me at this time. Same goes for z, since I have no idea about y's output.
So after I enter them in my template, the only thing that's really left for me is just to fill in the blanks for unknown values. Since x would require a as input, it means that there's an a right after it. Which would mean that it's z's input, too. Since it's z's input, I can assume it's y's output. The only thing left to fill in is z's output, and I just assign it a c since I don't really know what it could be.
As you can see, this isn't what the interpreter gives me, at all. While the left hand side might be still somewhat similar, I don't understand what happens on the right hand side, at all. Why is it d -> b? Shouldn't it be whatever's the result of (z(y(x))), which should have z's input/output?
Thanks in advance for any help you might offer me.
There are three basic properties you can exploit:
Due to currying, \x y -> z is equivalent to \x -> \y -> z.
For any x(y), you know that x must be a function and its first argument matches the type of the expression y.
You know the type of ., which is (b -> c) -> (a -> b) -> a -> c. Furthermore, . is right-associative (i.e. a.b.c is the same as a.(b.c)).
With this in mind, consider your first example:
t2 = ( \x y z -> y.x.y );
Clearly, it's a function of three arguments, so its type will be something akin to
t2 :: ty0 -> ty1 -> ty2 -> ty3
I use ty0 through ty3 here to denote the types to infer. ty0 is the type of the x argument, ty1 is for y, ty2 for z and ty3 is the type of the result value (i.e. the type of the expression y.x.y).
I'd start with determining the type ty3 (which is defined by the expression y.x.y) because while doing so you'll also find the types of the used arguments. Unused arguments can have any type:
y.x.y is equivalent to y.(x.y) (due to right-associativity of ., see item #3 above). So you can start by considering the subexpression x.y.
This means that x :: (b -> c) and y :: (a -> b) and hence x.y :: a -> c (due to the type of ., again see #3 above).
So we know that y :: (a -> b) and x.y :: a -> c. With this in mind, the only way y.(x.y) can type check (i.e. match the type of .) is when c ~ a, i.e. c and a are the same type.
Hence, x :: b -> a (our ty0!) and y :: a -> b (ty1) andy.(x.y) :: a -> b(what we calledty3` above). You can plug this into our primitive 'three-argument function type' above.
t2 :: ty0 -> ty1 -> ty2 -> ty3
=>
t2 :: (b -> a) -> (a -> b) -> ty2 -> (a -> b)
...and since -> is right-associative, you can omit the last parens (and instead of ty2 you could have used c, of course).
Let's try the same strategy on your last example:
tm2 = (\z -> \y -> \x -> z.y.x);
This is equivalent to \z y x -> z.y.x (due to currying, see #1 in the list at the top).
This means it's another three-argument function of the form tm2 :: ty0 -> ty1 -> ty2 -> ty3. Again, we start by inferring the type ty3 by considering the definition of the function.
The type ty3 is the type of the expression z.y.x, which is equivalent to z.(y.x) (due to right-associativity of .).
All three variables must be functions to satisfy the type of . (see #3 in the list at the top).
So x :: a -> b, y :: b -> c, y.x :: a -> c.
From this, it follows that z :: c -> d and hence z.y.x :: a -> d.
Since z is the first argument to tm2, y is the second and x is the third argument, you can tell that
tm2 :: (c -> d) -> (b -> c) -> (a -> b) -> (a -> d)

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

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.

Resources