Structural induction in haskell. Lists and sum - haskell

Hi I'm quite new to haskell and just got into structural induction and was wondering if someone could explain the steps I should take it would be very helpful.
Question:
-- computes the sum of all numbers in the list
sum :: [Integer] -> Integer
sum [] = 0
sum (x:xs) = x + sum xs
-- appends two lists
(++) :: [Integer] -> [Integer] -> [Integer]
[] ++ ys = ys
(x:xs) ++ ys = x : (xs ++ ys)
Prove (by using structural induction) that the following equation holds, for all lists of integers xs and ys:
sum (xs ++ ys) = sum xs + sum ys
Don't forget to state the I.H. in the induction step. Please also make sure you clearly state the reasons why you make the steps in your proofs.
My steps:
To prove:
sum (xs ++ ys) = sum xs + sum ys
Proof: by structural induction
Let P ( ) <--- dont really know what to type in there so if someone could take it from there I would appreciete it greatly!

++ is defined by induction on its first argument, xs, so this is usually a good sign that we need to proceed by induction on xs.
Hence, we fix ys once for all, and define P(xs) as follows
P(xs) = (sum (xs ++ ys) == sum xs + sum ys)
Now you have to prove that P(xs) holds for all xs. Apply the induction principle on lists and you should be OK.

Related

Haskell: Is it true that function application distributes over list concatenation?

After reading this question: Functional proofs (Haskell)
And after looking at the inductive proof of forall xs ys. length (xs ++ ys) = length xs + length ys from the Haskell School of Music (page 164).
It seemed to me that function application distributes over list concatenation.
Hence the more general law might be that forall f xs ys. f (xs ++ ys) = f xs ++ f ys.
But how would one prove/disprove such a predicate?
-- EDIT --
I made a typo it was meant to be: forall f xs ys. f (xs ++ ys) = f xs + f ys, which matches what the previous question and the Haskell SoM uses. That being said, because of this typo, it's no longer "distributivity" property. However, #leftaroundabout made the correct answer for my original typoed question. And as for my intended question, the law is still not correct, because functions don't need the preserve the structural value. The f might give a completely different answer depending on the length of the list it is applied to.
No, this is clearly not true in general:
f [_] = []
f l = l
then
f ([1] ++ [2]) = f [1,2] = [1,2]
but
f [1] ++ f [2] = [] ++ [] = []
I'm sure the functions which do have this problem form an interesting class, but general functions can do pretty much anything to a list's structure which thwarts such invariants.
And after looking at the inductive proof of forall xs ys. length (xs ++ ys) = length xs + length ys from the Haskell School of Music (page 164).
It seemed to me that function application distributes over list concatenation.
Well, clearly that is not the case. For example:
reverse ([1..3] ++ [4..6]) /= reverse [1..3] ++ reverse [4..6]
The example that you're quoting is a special case that's called a monoid morphism: a function f :: m -> n such that:
m and n are monoids with binary operation <> and identity mempty;
f mempty = mempty
f (m <> m') == f m <> f m'
So length :: [a] -> Int is a monoid morphism, sending [] to 0 and ++ to +:
length [] = 0
length (xs ++ ys) = length xs + length ys

How to multiply two elements of each pair from list of pairs - Haskell

I want to make function which returns list of multiplied elements from each pair from list of pairs. For example:
>product [1,2] [3,4]
[3,8]
I want to do this using list comprehension. I tried something like this:
product :: Num a => [a] -> [a] -> [a]
product xs ys = [x*y | z<-zip xs ys, (x, _)<-z, (_, y)<-z]
but it's not working. What should be changed?
As a rule of thumb, you should have one <- for each nested iteration. Since you only want to iterate over one list -- namely, zip xs ys -- there should be only one <-. Thus:
scalarproduct xs ys = sum [x*y | (x,y) <- zip xs ys]
You may also like the zipWith function:
scalarproduct xs ys = sum (zipWith (*) xs ys)
scalarproduct = (sum .) . zipWith (*) -- may be readable, depending on your bent
I want to do this using list comprehension. [...]
My advice is: don't! List comprehensions are a tool, and if they're not helping you, then use a different tool.
Simple solution:
product :: Num a => [a] -> [a] -> [a]
product xs ys = zipWith (*) xs ys

Union Function in Haskell

I have been getting my hands around coding in Haskell, but couldn't grasp the idea of implementing union function.
I have also found some function definition embedded inside the Haskell platform. but the problem is I need a neat and understandable way to make it work.
Anyone can help me with that?
Assuming you're talking about union :: Eq a => [a] -> [a] -> [a] which takes two input lists and returns a third list which contains all of the elements of each argument list, then it's defined in Data.List which is in the base package.
In the source it's divided into two functions, the generalized function unionBy which takes a custom definition of equality (a function of type equal to (==) :: a -> a -> Bool) and then defines the one that uses the Eq typeclass by passing in (==) as a concrete implementation of equality.
union :: (Eq a) => [a] -> [a] -> [a]
union = unionBy (==)
We can substitute (==) into the unionBy code, though, as Haskell lets us use equational reasoning.
union = unionBy (==)
-- so...
union :: Eq a => [a] -> [a] -> [a]
union xs ys = xs ++ foldl (flip (deleteBy (==))) (nubBy (==) ys) xs
This same pattern occurs twice more in the definition of unionBy in deleteBy and nubBy, both of which follow the same convention. delete removes an element from a list and nub returns a list of unique elements. We'll simplify the definition again to eliminate all traces of (==) and simply assume that the elements a have Eq defined.
union xs ys = xs ++ foldl (flip delete) (nub ys) xs
Now the definition is perhaps more readable. The union of xs and ys is xs appended to the unique ("nubbed") values of ys which have been processed by foldl (flip delete) _ xs. The net result of that foldl is to one by one try to delete each element of xs from (nub ys). What that ends up meaning is that union xs ys is xs appended to each unique element from ys less those in xs.
As an aside, with this source in hand we can notice some quirky behavior of union such as how it treats duplicates in the first argument differently from the second argument
union [1,1,2] [2] == [1,1,2]
union [2] [1,1,2] == [2,1]
which is a bit of a letdown, a result of using [] to represent a Set-like notion of union. However, if we view the results using Set.fromList then we're fine.
xs, ys :: Eq a => [a]
Set.fromList (xs `union` ys) == Set.fromList xs `Set.union` Set.fromList ys
which also gives us another definition of union
union xs ys = Set.toList (Set.fromList xs `Set.union` Set.fromList ys)
So how does that foldl trick work? Let's unpack the definition of foldl to see, again abusing equational reasoning.
union xs ys = xs ++ (case xs of
[] -> nub ys
(x:xs') -> foldl (flip delete) (delete x (nub ys)) xs'
)
which should make the trick more evident—it cycles over the elements of xs, deleting them one by one from (nub ys).
While hopefully this helped to make the code in union a bit more clear, the real take home should be that equational reasoning is a powerful tool for dissecting Haskell code. Don't be afraid to simplify code directly by manually inlining the definition of a function.
I am not sure if this union meets your requirements but it is rather simple.
I needed my own function to remove duplicates.
rmdups ls = [d|(z,d)<- zip [0..] ls,notElem d $ take z ls]
It does the same as any recursive function of the same purpose.
union l1 l2 = let l = l1 ++ l2 in rmdups l
I may have misinterpreted the question, but this was a post I found as I was trying to find how to write my own union function. I understand there is one built in but as someone who was trying to learn Haskell that doesn't help at all. These were the functions I wrote to make it work.
memberSet :: Int -> [Int] -> Bool
memberSet x [] = False
memberSet x (y:ys)
| x == y = True
| otherwise = memberSet x ys
unionSet :: [Int] -> [Int] -> [Int]
unionSet [] [] = []
unionSet (x:xs) [] = (x:xs)
unionSet [] (y:ys) = (y:ys)
unionSet (x:xs) (y:ys)
| memberSet y (x:xs) = unionSet (x:xs) ys
| otherwise = y : unionSet (x:xs) ys
main = do
print (unionSet [1,2,3] [2,5,3,4])
Member set checks if an element is present in a list (again I know there is a built in function to do this but I'm trying to learn). And there union set checks if the first elem of the second list is in the first list, if its not it adds it to a list and recursively calls itself. If it is in the first list, it skips that elem and recursively calls itself.
One problem I don't think anyone has addressed is that set union and intersection must be commutative and associative (Tom Apostol Calculus, p. 14).
λ> (Data.List.union [1,1,2] [2]) == (Data.List.union [2] [1,1,2])
False
λ> import Data.Set (Set, lookupMin, lookupMax)
λ> import qualified Data.Set as Set
λ> Set.union (Set.fromList [1, 3, 5, 7]) (Set.fromList [0, 2, 4, 6])
fromList [0,1,2,3,4,5,6,7]
λ> Set.union (Set.fromList [0, 2, 4, 6]) (Set.fromList [1, 3, 5, 7])
fromList [0,1,2,3,4,5,6,7]
So Data.List is not aware, but few more experiments would seem to demonstrate that Haskell Data.Set is aware. So another nail in the coffin of lists as sets, although I suppose we could kludge something further with lists.

Calculating list cumulative sum in Haskell

Write a function that returns the running sum of list. e.g. running [1,2,3,5] is [1,3,6,11]. I write this function below which just can return the final sum of all the values among the list.So how can i separate them one by one?
sumlist' xx=aux xx 0
where aux [] a=a
aux (x:xs) a=aux xs (a+x)
I think you want a combination of scanl1 and (+), so something like
scanl1 (+) *your list here*
scanl1 will apply the given function across a list, and report each intermediate value into the returned list.
Like, to write it out in pseudo code,
scanl1 (+) [1,2,3]
would output a list like:
[a, b, c] where { a = 1, b = a+2, c = b+3 }
or in other words,
[1, 3, 6]
Learn You A Haskell has a lot of great examples and descriptions of scans, folds, and much more of Haskell's goodies.
Hope this helps.
You can adjust your function to produce a list by simply prepending a+x to the result on each step and using the empty list as the base case:
sumlist' xx = aux xx 0
where aux [] a = []
aux (x:xs) a = (a+x) : aux xs (a+x)
However it is more idiomatic Haskell to express this kind of thing as a fold or scan.
While scanl1 is clearly the "canonical" solution, it is still instructive to see how you could do it with foldl:
sumList xs = tail.reverse $ foldl acc [0] xs where
acc (y:ys) x = (x+y):y:ys
Or pointfree:
sumList = tail.reverse.foldl acc [0] where
acc (y:ys) x = (x+y):y:ys
Here is an ugly brute force approach:
sumList xs = reverse $ acc $ reverse xs where
acc [] = []
acc (x:xs) = (x + sum xs) : acc xs
There is a cute (but not very performant) solution using inits:
sumList xs = tail $ map sum $ inits xs
Again pointfree:
sumList = tail.map sum.inits
Related to another question I found this way:
rsum xs = map (\(a,b)->a+b) (zip (0:(rsum xs)) xs)
I think it is even quite efficient.
I am not sure how canonical is this but it looks beautiful to me :)
sumlist' [] = []
sumlist' (x:xs) = x : [x + y | y <- sumlist' xs]
As others have commented, it would be nice to find a solution that is both linear and non-strict. The problem is that the right folds and scans do not allow you to look at items to the left of you, and the left folds and scans are all strict on the input list. One way to achieve this is to define our own function which folds from the right but looks to the left. For example:
sumList:: Num a => [a] -> [a]
sumList xs = foldlr (\x l r -> (x + l):r) 0 [] xs
It's not too difficult to define foldr so that it is non-strict in the list. Note that it has to have two initialisers -- one going from the left (0) and one terminating from the right ([]):
foldlr :: (a -> b -> [b] -> [b]) -> b -> [b] -> [a] -> [b]
foldlr f l r xs =
let result = foldr (\(l', x) r' -> f x l' r') r (zip (l:result) xs) in
result

Functional proofs (Haskell)

I failed at reading RWH; and not one to quit, I ordered Haskell: The Craft of Functional Programming. Now I'm curious about these functional proofs on page 146. Specifically I'm trying to prove 8.5.1 sum (reverse xs) = sum xs. I can do some of the induction proof but then I get stuck..
HYP:
sum ( reverse xs ) = sum xs
BASE:
sum ( reverse [] ) = sum []
Left = sum ( [] ) (reverse.1)
= 0 (sum.1)
Right = 0 (sum.1)
INDUCTION:
sum ( reverse (x:xs) ) = sum (x:xs)
Left = sum ( reverse xs ++ [x] ) (reverse.2)
Right = sum (x:xs)
= x + sum xs (sum.2)
So now I'm just trying ot prove that Left sum ( reverse xs ++ [x] ) is equal to Right x + sum xs, but that isn't too far off from where I started sum ( reverse (x:xs) ) = sum (x:xs).
I'm not quite sure why this needs to be proved, it seems totally reasonable to use the symbolic proof of reverse x:y:z = z:y:x (by defn), and because + is commutative (arth) then reverse 1+2+3 = 3+2+1,
sum (reverse []) = sum [] -- def reverse
sum (reverse (x:xs)) = sum (reverse xs ++ [x]) -- def reverse
= sum (reverse xs) + sum [x] -- sum lemma below
= sum (reverse xs) + x -- def sum
= x + sum (reverse xs) -- commutativity assumption!
= x + sum xs -- inductive hypothesis
= sum (x:xs) -- definition of sum
However, there are underlying assumptions of associativity and commutativity that are not strictly warranted and this will not work properly for a number of numerical types such as Float and Double where those assumptions are violated.
Lemma: sum (xs ++ ys) == sum xs + sum ys given the associativity of (+)
Proof:
sum ([] ++ ys) = sum ys -- def (++)
= 0 + sum ys -- identity of addition
= sum [] ++ sum ys -- def sum
sum ((x:xs) ++ ys) = sum (x : (xs ++ ys)) -- def (++)
= x + sum (xs ++ ys) -- def sum
= x + (sum xs + sum ys) -- inductive hypothesis
= (x + sum xs) + sum ys -- associativity assumption!
= sum (x:xs) + sum ys -- def sum
Basically you need to show that
sum (reverse xs ++ [x]) = sum (reverse xs) + sum [x]
which then easily leads to
= x + sum (reverse xs)
= x + sum xs -- by inductive hyp.
The problem is to show that sum distributes over list concatenation.
Use the definition of a sum to break up (sum reverse xs ++[x]) into x + sum(reverse(xs)), and using your inductive hypothesis you know sum(reverse(xs)) = sum(xs). But I agree, induction is overkill for a problem like this.
Here's where I think you're stuck. You need to prove a lemma that says
sum (xs ++ ys) == sum xs + sum ys
To prove this law you will have to assume that addition is associative, which is true only for integers and rationals.
Then, you will also need to assume that addition is commutative, which is true for integers and rationals but also for floats.
Digression: The style of your proofs looks very strange to me. I think you will have an easier time writing these kinds of proofs if you use the style in Graham Hutton's book.

Resources