2

Given the following function:

let rec foo l1 l2 = 
    match (l1,l2) with
        ([],ys) -> ys
      | (x::xs,ys) -> foo xs (x::ys))

Prove the following property:

  • foo (foo xs ys) zs = foo ys (xs@zs)

So far, I have completed the base case and inductive case, but have no idea how to start the proof:

Base Case:

  • foo (foo [] ys) zs = foo ys ([]@zs)
  • foo ys zs = foo ys zs

Inductive Case:

  • foo (foo (x::xs) ys) zs = foo ys ((x::xs)@zs)
sshine
  • 15,635
  • 1
  • 41
  • 66
David Farthing
  • 237
  • 2
  • 13
  • I believe you have written the statements of *what is to be proved* in the base case and the inductive case, not *completed* either one of them. Furthermore, your goal for the inductive case should be of the form "if (something is true of `xs`) then (something similar is true of `x::xs`)". Right now, you are missing the first half. – antron Feb 04 '16 at 18:42
  • This `foo` function is `List.rev_append` from the standard library -- it reverses `l1` and concatenates it to `l2`, this observation could have guided the proof in the right direction. – Anton Trunov Jun 30 '16 at 19:49

2 Answers2

1

An outline of the kind of proof you are asking about follows. I included the base case. The inductive case is left for you. Make sure you use the assumption mentioned in the outline somewhere in the inductive case to complete it. I am using = for "equality" and => for evaluation. I don't know what relations are available in your context, what you are allowed to assume about evaluation and equality, or whether you are allowed to use lemmas about @ or have an abstract definition available. So, you will likely have to modify this.

Proof by induction on the structure of xs.

Case: xs = []:

foo (foo xs ys) zs
  =  foo (foo [] ys) zs          (* structure of xs *)
  => foo (match ([], ys) with ([], ys) -> ys | (* ... *)
                                 (* def. of foo, substitution *)
  => foo (ys) zs                 (* eval. of match *)
  =  foo ys zs                   (* drop parentheses *)
  =  foo ys ([] @ zs)            (* abstract def. of @ *)
  =  foo ys (xs @ zs)            (* structure of xs *)

Case: xs = x::xs':

Here, suppose that, for all ys, zs, foo (foo xs' ys) zs = foo ys (xs' @ zs). (This is the so-called inductive hypothesis.)

foo (foo xs ys) zs
  =  foo (foo (x::xs') ys) zs    (* structure of xs *)
  =  foo (match (x::xs', ys) with (* ... *) | (x::xs', ys) -> (* ... *)
                                 (* def. of foo, substitution *)
  => foo (foo xs' (x::ys)) zs    (* eval. of match *)

    (* for you *)

  =  foo ys ((x::xs') @ zs)      (* by some argument from you *)
  =  foo ys (xs @ zs)            (* structure of xs *)

As you can see, the proof starts by picking a value to do structural induction on (you already picked xs in your question). Then, the proof splits into cases according to all the possible ways xs might be constructed. Since xs is presumably a list (this is why type information is important), there are only two kinds of things it could be: it might be [], or it might be x::xs' for some value x and list xs'. This results in the base case and the inductive case, respectively. In both cases, we have to prove the same original property, but we know extra information about what xs looks like (i.e., the "structure" of xs).

For each case, you use the structure to figure out the statement you want to get to (approximately correct in your original question). Then, you try to simply go from the expression on the left side of the statement to the expression on the right side, using the rules of evaluation, identity, and any lemmas you have available. In the inductive case, you have an additional fact you can use about xs' (the "inductive hypothesis"). This "direct" approach isn't going to work in all (perhaps most) cases at the level of research, but it works fine for this exercise.

The actual statements proved in the cases are

  1. If xs = [], foo (foo xs ys) zs = foo ys (xs @ zs); and
  2. If xs = x::xs' and foo (foo xs' ys) zs = foo ys (xs' @ zs), then foo (foo xs ys) zs = foo ys (xs @ zs).

ys and zs are implicitly universally quantified.

antron
  • 3,749
  • 2
  • 17
  • 23
0
Claim: forall xs, ys, zs, foo (foo xs ys) zs = foo ys (xs@zs)
Proof: By induction on xs
P(xs): forall ys, zs, foo (foo xs ys) zs = foo ys (xs@zs)
P([]): forall ys, zs, foo (foo [] ys) zs = foo ys ([]@zs)
LHS: 
= foo (foo [] ys) zs
= foo (ys) zs
= foo ys zs 
RHS:
= foo ys ([]@zs)
= foo ys zs {eval @}
= LHS
IC: xs=h::t
IH: P(t): forall ys, zs, foo (foo t ys) zs = foo ys (t@zs)
Show: P(h::t): forall ys, zs, foo (foo h::t ys) zs = foo ys (h::t@zs)
LHS:
= foo (foo h::t ys) zs
= foo (foo t (h::ys)) zs
= foo (h::ys) (t@zs) {IH with ys:=h::ys}
= foo ys (h::t@zs) {eval of foo}
= RHS

RHS:
= foo ys (h::t@zs)
= LHS

QED
  • Hey there. Welcome to the stackoverflow! thank you for responding and answering to questions. please add some explanation to your code to be more helpful. Thank you. – El.Hum Nov 05 '22 at 05:40