Is the following a definition of structural induction?
foldr f a (xs::ys) = foldr f (foldr f a ys) xs
Can someone give me an example of structural induction in Haskell?
You did not specify it, but I will assume :: means list concatention and
use ++, since that is the operator used in Haskell.
To prove this, we will perform induction on xs. First, we show that the
statement holds for the base case (i.e. xs = [])
foldr f a (xs ++ ys)
{- By definition of xs -}
= foldr f a ([] ++ ys)
{- By definition of ++ -}
= foldr f a ys
and
foldr f (foldr f a ys) xs
{- By definition of xs -}
= foldr f (foldr f a ys) []
{- By definition of foldr -}
= foldr f a ys
Now, we assume that the induction hypothesis foldr f a (xs ++ ys) = foldr
f (foldr f a ys) xs holds for xs and show that it will hold for the list
x:xs as well.
foldr f a (x:xs ++ ys)
{- By definition of ++ -}
= foldr f a (x:(xs ++ ys))
{- By definition of foldr -}
= x `f` foldr f a (xs ++ ys)
^------------------ call this k1
= x `f` k1
and
foldr f (foldr f a ys) (x:xs)
{- By definition of foldr -}
= x `f` foldr f (foldr f a ys) xs
^----------------------- call this k2
= x `f` k2
Now, by our induction hypothesis, we know that k1 and k2 are equal,
therefore
x `f` k1 = x `f` k2
Thus proving our hypothesis.
Related
This question already has answers here:
Use foldr to define map in Haskell,
(3 answers)
Closed 3 months ago.
I'm new to Haskell and I want to understand what this syntax means.
This is the context of the function:
map' :: (a -> b) -> [a] -> [b]
map' f xs = foldr (\y ys -> (f y):ys) [] xs
It's defining the map function from the prelude in terms of foldr. I'm confused by what foldr (\y ys -> (f y):ys) [] xs means. Especially the (\y ys -> (f y): ys) part.
In my understanding, y is the first value in the list ys which is the input and the function f is being applied to the y value in the list ys. I understand these values are taken in the context of pattern matching. Kindly correct me if I'm wrong.
Take a look at a simplified definition of foldr (adapted from https://wiki.haskell.org/Foldr_Foldl_Foldl'):
foldr _ z [] = z
foldr f z (x:xs) = f x (foldr f z xs)
The second argument passed to f (ys, in your case) is basically the result of folding the rest of the list, without having to explicitly make the recursive call.
We can compare an explicitly recursive definition of map':
map' f [] = []
map' f (x:xs) = f x : map' xs
to the expansion of your definition of map' using equational reasoning.
map' f (x:xs)
-- by definition of map'
== foldr (\y ys -> f y : ys) [] (x:xs)
-- by definition of foldr
== (\y ys -> f y : ys) x (foldr (\y ys -> f y : ys) [] xs)
-- application of folding function to x...
== (\ys -> f x : ys) (foldr (\y ys -> f y : ys) [] xs)
-- ... and then the recursive fold
== f x : foldr (\y ys -> f y : ys) [] xs
-- by definition of map'
== f x : map' f xs
Having a hard time understanding fold... Is the expansion correct ? Also would appreciate any links, or analogies that would make fold more digestible.
foldMap :: (a -> b) -> [a] -> [b]
foldMap f [] = []
foldMap f xs = foldr (\x ys -> (f x) : ys) [] xs
b = (\x ys -> (f x):ys)
foldMap (*2) [1,2,3]
= b 1 (b 2 (foldr b [] 3))
= b 1 (b 2 (b 3 ( b [] [])))
= b 1 (b 2 ((*2 3) : []))
= b 1 ((*2 2) : (6 :[]))
= (* 2 1) : (4 : (6 : []))
= 2 : (4 : (6 : []))
First, let's not use the name foldMap since that's already a standard function different from map. If you want to re-implement an existing function with the same or similar semantics, convention is to give it the same name but either in a separate module, or with a prime ' appended to the name. Also, we can omit the empty-list case, since you can just pass that to the fold just as well:
map' :: (a -> b) -> [a] -> [b]
map' f xs = foldr (\x ys -> f x : ys) [] xs
Now if you want to evaluate this function by hand, first just use the definition without inserting anything more:
map' (*2) [1,2,3,4]
≡ let f = (*2)
xs = [1,2,3,4]
in foldr (\x ys -> (f x) : ys) [] xs
≡ foldr (\x ys -> (*2) x : ys) [] [1,2,3,4]
Now just prettify a bit:
≡ foldr (\x ys -> x*2 : ys) [] [1,2,3,4]
Now to evaluate this through, you also need the definition of foldr. It's actually a bit different in GHC, but effectively
foldr _ z [] = z
foldr f z (x:xs) = f x (foldr f z xs)
So with your example
...
≡ foldr (\x ys -> x*2 : ys) [] (1:[2,3,4])
≡ (\x ys -> x*2 : ys) 1 (foldr (\x ys -> x*2 : ys) [] [2,3,4])
Now we can perform a β-reduction:
≡ 1*2 : foldr (\x ys -> x*2 : ys) [] [2,3,4]
≡ 2 : foldr (\x ys -> x*2 : ys) [] [2,3,4]
...and repeat for the recursion.
foldr defines a family of equations,
foldr g n [] = n
foldr g n [x] = g x (foldr g n []) = g x n
foldr g n [x,y] = g x (foldr g n [y]) = g x (g y n)
foldr g n [x,y,z] = g x (foldr g n [y,z]) = g x (g y (g z n))
----- r ---------
and so on. g is a reducer function,
g x r = ....
accepting as x an element of the input list, and as r the result of recursively processing the rest of the input list (as can be seen in the equations).
map, on the other hand, defines a family of equations
map f [] = []
map f [x] = [f x] = (:) (f x) [] = ((:) . f) x []
map f [x,y] = [f x, f y] = ((:) . f) x (((:) . f) y [])
map f [x,y,z] = [f x, f y, f z] = ((:) . f) x (((:) . f) y (((:) . f) z []))
= (:) (f x) ( (:) (f y) ( (:) (f z) []))
The two families simply exactly match with
g = ((:) . f) = (\x -> (:) (f x)) = (\x r -> f x : r)
and n = [], and thus
foldr ((:) . f) [] xs == map f xs
We can prove this rigorously by mathematical induction on the input list's length, following the defining laws of foldr,
foldr g n [] = []
foldr g n (x:xs) = g x (foldr g n xs)
which are the basis for the equations at the top of this post.
Modern Haskell has Fodable type class with its basic fold following the laws of
fold(<>,n) [] = n
fold(<>,n) (xs ++ ys) = fold(<>,n) xs <> fold(<>,n) ys
and the map is naturally defined in its terms as
map f xs = foldMap (\x -> [f x]) xs
turning [x, y, z, ...] into [f x] ++ [f y] ++ [f z] ++ ..., since for lists (<>) == (++). This follows from the equivalence
f x : ys == [f x] ++ ys
This also lets us define filter along the same lines easily, as
filter p xs = foldMap (\x -> [x | p x]) xs
To your specific question, the expansion is correct, except that (*2 x) should be written as ((*2) x), which is the same as (x * 2). (* 2 x) is not a valid Haskell (though valid Lisp :) ).
Functions like (*2) are known as "operator sections" -- the missing argument goes into the empty slot: (* 2) 3 = (3 * 2) = (3 *) 2 = (*) 3 2.
You also asked for some links: see e.g. this, this and this.
I'm trying to define primitive recursion in term of foldr, as explained in A tutorial on the universality and expressiveness on fold chapter 4.1.
Here is first attempt at it
simpleRecursive f v xs = fst $ foldr g (v,[]) xs
where
g x (acc, xs) = (f x xs acc,x:xs)
However, above definition does not halt for head $ simpleRecursive (\x xs acc -> x:xs) [] [1..]
Below is definition that halt
simpleRecursive f v xs = fst $ foldr g (v,[]) xs
where
g x r = let (acc,xs) = r
in (f x xs acc,x:xs)
Given almost similar definition but different result, why does it differ? Does it have to do with how Haskell pattern match?
The crucial difference between the two functions is that in
g x r = let (acc, xs) = r
in (f x xs acc, x:xs)
The pattern match on the tuple constructor is irrefutable, whereas in
g x (acc, xs) = (f x xs acc, x:xs)
it is not. In other words, the first definition of g is equivalent to
g x ~(acc, xs) = (f x xs acc, x:xs)
I understand the definitions of foldl, foldr, but I have problems with functions defined by them.
For example map with foldr:
map f [] = []
map f l = foldr (\x xs -> f x : xs) [] l
I don't understand the (\x xs -> f x : xs). It is the map function, which foldr takes? But shouldn't it be (\x xs -> f x : f xs), because map f (x:xs) = f x : map f xs?
Example with foldl:
concat (x:xs) = x ++ concat xs
concat' xs = foldl (++) [] xs
concat'' xs = foldl (\ys y -> ys ++ y) [] xs
Of course I understand (++), but what's the logic behind (\ys y -> ys ++ y)? Is it ys = [] and y = xs?
So the function takes [] as ys and y is the first element of xs and concates the [] with the y?
Concrete example:
concat'' [1,2,3] = foldl (\ys y -> ys ++ y) [] [1,2,3]
=> foldl (\ys y -> ys ++ y) ((\ys y -> ys ++ y) [] [1]) [2,3]
=> foldl (\ys y -> ys ++ y) [1] [2,3]
=> foldl (\ys y -> ys ++ y) ((\ys y -> ys ++ y) [1] [2]) [3]
=> foldl (\ys y -> ys ++ y) [1,2] [3]
=> foldl (\ys y -> ys ++ y) ((\ys y -> ys ++ y) [1,2] [3]) []
=> foldl (\ys y -> ys ++ y) [1,2,3] []
=> [1,2,3]
Another thing: concat only takes 1 list xs, so if I want to concat 2 lists?
concat (x:xs) ys = x ++ concat xs ys
concat [1,2,3] [4,5,6] with foldl?
Reverse:
reverse (x:xs) = reverse xs ++ [x]
reverse' l = foldl (\xs x -> [x] : xs) [] l
reverse'' l = foldr (\x xs -> xs ++ [x]) [] l
The foldr is intuitive clear (with the questions from above), but what's behind the reverse order in foldl (\xs x -> [x] : xs)? This foldl (\x xs -> xs ++ [x]) [] l would be wrong, wouldn't it?
Thanks a lot!
The code
foldr (\x xs -> ...) end list
could be read, roughly, as follows
scan the whole list
if it's empty, just return end end
otherwise:
let x be the element at hand
let xs be the rest of the list, after having been processed
apply the ... operation
The emphasized part is crucial. xs is not the rest of the list, but the result of the "recursive call" on it.
Indeed, xs is a bad name for that. In thee general case, it's not even a list! E.g. one would never write (silly example)
foldr (\x xs -> x + xs) 0 [1..100] -- sum 1..100
but rather prefer something like
foldr (\x partialSum -> x + partialSum) 0 [1..100] -- sum 1..100
(Actually, one would not sum using foldr, but let's leave that aside.)
So, just read it like this:
map f l = foldr (\x mappedTail -> f x : mappedTail) [] l
Exercise 1 at page 102 of the Haskell Wikibook asks "Write your own definition of scanr, first using recursion, and then using foldr." I wrote a recursive one:
myscan f acc [] = [acc]
myscan f acc (x:xs) = val : rest where
val = f x (head rest)
rest = myscan f acc xs
...but couldn't figure out a foldr version. I eventually Googled and found this answer:
myscan2 f acc xs = foldr f' [acc] xs where
f' x xs = (f x (head xs)) : xs
Obviously it works but it doesn't make sense to me. Using parameters
(+) 0 [1,2,3]
...it becomes something like this:
myscan2 (+) 0 [1,2,3] = foldr f' [0] [1,2,3] where
f' [0] [1,2,3] = ((+) [0] (head [1,2,3])) : [1,2,3]
...but ((+) [0] (head [1,2,3])) part is not type compatible for (+). Yet, the function works, so what am I reading or converting incorrectly?
The matter on the function you found is:
The xs on myscan2 f acc xs = foldr f' [acc] xs is not the same on
f' x xs = (f x (head xs)) : xs.
They are completly diferent. Maybe you could understand better if it looks like:
myscanr f acc xs = foldr f' [acc] xs
where f' b a = (f b (head a)) : a
What it does, change the accumulator to a list, because scanl accumlate but it keep all the path going through the original list. So, f' cons (:) a new head applying the function f to the actual element of the list and the head of accumulator.