2

I have the following:

elem :: Eq a => a -> [a] -> Bool
elem _ [] = False
elem x (y:ys) = x == y || elem x ys

How can I prove that for all x's y's and z's...

elem z (xs ++ ys) == elem z xs || elem z ys

I attempted to make the left side equivalent to the right side, however none of my attempts have been fruitful.

L.S elem z (x:xs ++ y:ys) = z==x || z==y || elem xs || elem ys

R.S elem z (x:xs) || elem z (y:ys) = z==x || z==y || elem xs || elem ys

Can someone help me out?

jub0bs
  • 60,866
  • 25
  • 183
  • 186
buydadip
  • 8,890
  • 22
  • 79
  • 154

4 Answers4

5

Here's a hint.

The ++ operator is defined by induction over the first argument:

[]     ++ ys = ys
(x:xs) ++ ys = x : (xs ++ ys)

You want to prove

elem z (xs ++ ys) == elem z xs || elem z ys

which is a property of z, xs and ys. Let's call it p(z,xs,ys). Moreover, the first argument of ++ is xs, so this suggests to proceed by induction on xs.

We need to prove:

  1. base case: p(z,[],ys).
  2. inductive case: p(z,x:xs,ys) assuming the induction hypothesis p(z,xs,ys)

You will also need to exploit the definition of elem at some point.

chi
  • 111,837
  • 3
  • 133
  • 218
3

Equational reasoning is fun! You'll get the knack of it pretty quickly, if you do a few proofs yourself. I warmly recommend ch. 13 of Graham Hutton's Programming in Haskell for a concise introduction.

Anyway, you can prove that, for all equatable and finite (see Tom Ellis's answer) xs, ys and z,

elem z (xs ++ ys) == elem z xs || elem z ys

by induction on list xs. For that, you need to use the definitions of ++, ||, and elem, and use the fact that || is associative:

[]     ++ ys = ys
(x:xs) ++ ys = x : (xs ++ ys)

False || b = b
True  || _ = True

elem _ [] = False
elem x (y:ys) = x == y || elem x ys

Base case

Let ys be a value of type Eq a => [a], and z a value of type Eq a => a; then we have

elem z ([] ++ ys)
=     {applying ++}
elem z ys
=     {unapplying ||}
False || elem z ys
=     {unapplying elem}
elem z [] || elem z ys

Inductive case

Let xs, ys be values of type Eq a => [a], and x, z values of type Eq a => a. Assume (induction hypothesis) that

elem z (xs ++ ys) == elem z xs || elem z ys

Then we have

elem z ((x:xs) ++ ys)
=     {applying ++)
elem z (x : (xs ++ ys))
=     {applying elem}
z == x || elem (xs ++ ys)
=     {induction hypothesis}
z == x || (elem z xs || elem z ys)
=     {associativity of ||}
(z == x || elem z xs) || elem z ys
=     {unapplying elem}
elem z (x:xs) || elem z ys

(QED)

Community
  • 1
  • 1
jub0bs
  • 60,866
  • 25
  • 183
  • 186
2

To expand on accepted answer, this equation is also true when xs is infinite. If elem z xs = True, then elem z (xs ++ ys) = True = elem z xs || elem z ys. Otherwise, elem z (xs ++ ys) = ⊥ = elem z xs || elem z ys, which can be easily verified in ghci.

  • 1
    "easily verified in ghci" is an overstatement: you can not really check if a program diverges on an infinite list by just running it. I do concede that, in practice, if such a simple example does not halt in a few seconds, I'd be inclined to believe that it will never halt. – chi Mar 07 '15 at 00:03
1

Lists in Haskell do not satisfy the principle of induction because Haskell is a lazy language and lists may be infinite. Instead I believe you should just write two expressions in the same form to show that they are equivalent. The desired form is

f [] = z
f (x:xs) = g x (f xs)

To use this approach to prove the desired result take

f xs = elem z (xs ++ ys)
f' xs = elem z xs || elem z ys

Note that by pattern matching on xs and using the definitions of (++) and elem these are equivalent to

f [] = elem z ys
f (x:xs) = x == z || elem z (xs ++ ys)

f' [] = elem z ys
f' (x:xs) = x == z || elem z xs || elem z ys

We can rewrite the recursive calls as

f [] = elem z ys
f (x:xs) = x == z || f xs

f' [] = elem z ys
f' (x:xs) = x == z || f' xs

If we define g x rest = x == z || rest then

f [] = elem z ys
f (x:xs) = g x (f xs)

f' [] = elem z ys
f' (x:xs) = g x (f' xs)

and then note that the expressions for f and f' are equal.

My previous answer was incorrect:

It's not true. Consider xs = repeat 0 ys = [1] z = 1 Then elem z ys = elem 1 [1] = True so elem z xs || elem z ys = True but elem z (xs ++ ys) = elem 1 (repeat 0 ++ [1]) = False because the search for `1` in `repeat 0` never terminates. This is an archetypal example of why the equational theory for lazy languages is less rich than for strict languages. As suggested by the other answers you can prove your theorem for *finite* `xs` by structural induction. But that's somewhat begging the question. What's a *finite* list?
Tom Ellis
  • 9,224
  • 1
  • 29
  • 54
  • You write *the search for `1` in `[0..]` never terminates*, but because `1` is an element of `[0...]` and `||` is lazy in its second argument, it *does* terminate. Did you mean `[0,-1..]` instead? – jub0bs Mar 05 '15 at 20:39
  • I disagree. `elem 1 (repeat 0) || elem 1 [1]` is bottom, not `True`. Similarly, `elem 1 (repeat 0 ++ [1])` is bottom, not `False`. So this is not a counterexample to the claim. See also @user4640123's answer. – chi Mar 06 '15 at 23:59