Expr_annotated.v. Expr_annotated.v. Printed by Zach Tatlock

Similar documents
MoreIntro.v. MoreIntro.v. Printed by Zach Tatlock. Oct 07, 16 18:11 Page 1/10. Oct 07, 16 18:11 Page 2/10. Monday October 10, 2016 lec02/moreintro.

L04_in_class.v. L04_in_class.v. Printed by Zach Tatlock

L06_exercise.v. L06_exercise.v

MoreIntro_annotated.v. MoreIntro_annotated.v. Printed by Zach Tatlock. Oct 04, 16 21:55 Page 1/10

CS 456 (Fall 2018) Scribe Notes: 2

CIS 500: Software Foundations

CIS 500: Software Foundations

c constructor P, Q terms used as propositions G, H hypotheses scope identifier for a notation scope M, module identifiers t, u arbitrary terms

Coq quick reference. Category Example Description. Inductive type with instances defined by constructors, including y of type Y. Inductive X : Univ :=

Introduction to dependent types in Coq

CIS 500 Software Foundations. Midterm I. (Standard and advanced versions together) October 1, 2013 Answer key

Certified Programming with Dependent Types

Now that we have keys defined for the maps, we can start talking about maps. The first of these are Total Maps. Total Maps are defined as follows:

CIS 500: Software Foundations

Inductive Definitions, continued

Printed by Zach Tatlock Dec 08, 15 22:18 Page 1/11. Lemma subst_only_free: forall e1 e2 x e3, Subst e1 e2 x e3 > ~ free e1 x > e1 = e3. Proof.

4 Programming with Types

LASER 2011 Summerschool Elba Island, Italy Basics of COQ

Inductive prod (A B : Set) : Set := pair : A -> B -> prod A B. Inductive sum (A B : Set) : Set := inl : A -> sum A B inr : B -> sum A B.

Infinite Objects and Proofs 1

3 Pairs and Lists. 3.1 Formal vs. Informal Proofs

Coq in a Hurry. Yves Bertot

Coq in a Hurry. Yves Bertot. To cite this version: HAL Id: inria v6

Verification in Coq. Prof. Clarkson Fall Today s music: Check Yo Self by Ice Cube

Programming Languages Fall 2014

HOL DEFINING HIGHER ORDER LOGIC LAST TIME ON HOL CONTENT. Slide 3. Slide 1. Slide 4. Slide 2 WHAT IS HIGHER ORDER LOGIC? 2 LAST TIME ON HOL 1

Induction in Coq. Nate Foster Spring 2018

Coq in a Hurry. Yves Bertot. October 2008

6.001 Notes: Section 8.1

Theorem Proving Principles, Techniques, Applications Recursion

Programming with (co-)inductive types in Coq

Induction and Semantics in Dafny

Printed by Zachary Tatlock Nov 04, 16 8:59 Page 1/9. (** Call By Value << v ::= \ x. e e1 > e1 e1 e2 > e1 e2 e2 > e2 v e2 > v e2

Analysis of dependent types in Coq through the deletion of the largest node of a binary search tree

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Sections p.

Inductive data types

Provably Correct Software

Reasoning About Programs Panagiotis Manolios

Summer 2017 Discussion 10: July 25, Introduction. 2 Primitives and Define

Programming Languages Third Edition

CIS 194: Homework 8. Due Wednesday, 8 April. Propositional Logic. Implication

GADTs. Wouter Swierstra. Advanced functional programming - Lecture 7. Faculty of Science Information and Computing Sciences

Notes for Recitation 8

CMSC 330: Organization of Programming Languages

Programming Languages Fall 2013

Intro. Scheme Basics. scm> 5 5. scm>

Proving Theorems with Athena

AXIOMS FOR THE INTEGERS

Overview. A Compact Introduction to Isabelle/HOL. Tobias Nipkow. System Architecture. Overview of Isabelle/HOL

CS152: Programming Languages. Lecture 11 STLC Extensions and Related Topics. Dan Grossman Spring 2011

A Coq tutorial for confirmed Proof system users

Lecture Notes on Induction and Recursion

Coq projects for type theory 2018

CSE 413 Languages & Implementation. Hal Perkins Winter 2019 Structs, Implementing Languages (credits: Dan Grossman, CSE 341)

Programming with Universes, Generically

Work-in-progress: "Verifying" the Glasgow Haskell Compiler Core language

Lecture 3: Recursion; Structural Induction

Automated Reasoning. Natural Deduction in First-Order Logic

Formal Semantics. Prof. Clarkson Fall Today s music: Down to Earth by Peter Gabriel from the WALL-E soundtrack

Mathematics for Computer Scientists 2 (G52MC2)

Coq Summer School. Yves Bertot

The Coq Proof Assistant A Tutorial

Lean 2 Quick Reference

Combining Programming with Theorem Proving

Type-directed Syntax Transformations for ATS-style Programs with Proofs

Programming with Math and Logic

CS 320 Homework One Due 2/5 11:59pm

Coq in a Hurry. Yves Bertot. HAL Id: inria v5

Propositional Calculus. Math Foundations of Computer Science

Type Checking. Outline. General properties of type systems. Types in programming languages. Notation for type rules.

CSE413: Programming Languages and Implementation Racket structs Implementing languages with interpreters Implementing closures

CSCC24 Functional Programming Scheme Part 2

Lecture 6: Sequential Sorting

Natural Numbers. We will use natural numbers to illustrate several ideas that will apply to Haskell data types in general.

Outline. General properties of type systems. Types in programming languages. Notation for type rules. Common type rules. Logical rules of inference

CMSC 330: Organization of Programming Languages. Operational Semantics

STABILITY AND PARADOX IN ALGORITHMIC LOGIC

Reasoning About Programs Panagiotis Manolios

Propositional Logic Formal Syntax and Semantics. Computability and Logic

Advanced Features: Type Classes and Relations

Proofwriting Checklist

Definition: A context-free grammar (CFG) is a 4- tuple. variables = nonterminals, terminals, rules = productions,,

Lectures 12 and 13 and 14: Regular Expression Matching; Staging

Intro to semantics; Small-step semantics Lecture 1 Tuesday, January 29, 2013

15 212: Principles of Programming. Some Notes on Continuations

CS103 Handout 29 Winter 2018 February 9, 2018 Inductive Proofwriting Checklist

6.001 Notes: Section 15.1

CMSC 330: Organization of Programming Languages. Formal Semantics of a Prog. Lang. Specifying Syntax, Semantics

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 1/38

Type families and data kinds

A Simple Supercompiler Formally Verified in Coq

Introduction to Co-Induction in Coq

Basic Foundations of Isabelle/HOL

GADTs. Wouter Swierstra and Alejandro Serrano. Advanced functional programming - Lecture 7. [Faculty of Science Information and Computing Sciences]

Parsing Combinators: Introduction & Tutorial

Review. CS152: Programming Languages. Lecture 11 STLC Extensions and Related Topics. Let bindings (CBV) Adding Stuff. Booleans and Conditionals

CS 4110 Programming Languages & Logics. Lecture 17 Programming in the λ-calculus

Types and Static Type Checking (Introducing Micro-Haskell)

SCHEME AND CALCULATOR 5b

CS 3512, Spring Instructor: Doug Dunham. Textbook: James L. Hein, Discrete Structures, Logic, and Computability, 3rd Ed. Jones and Barlett, 2010

Transcription:

Oct 05, 16 8:02 Page 1/14 * Lecture 03 Include some useful libraries. Require Import Bool. Require Import List. Require Import String. Require Import ZArith. Require Import Omega. List provides the cons notation "::": [x :: xs] is the same as [cons x xs] Fixpoint my_length {A: Type} (l: list A) : nat := match l with nil => O x :: xs => S (my_length xs) Oct 05, 16 8:02 Page 2/14 constructor. Alternatively, we could have explicitly told Coq exactly which constructor to use with: exact I. [myfalse] is also a proposition. It has ZERO constructors. That means there is no way to produce a value of type [myfalse]. Since a proposition [P] is true only when we can produce a value of type [P], we know that [myfalse] is in fact false. Inductive myfalse : Prop :=. List provides the append notation "++": [xs ++ ys] is the same as [app xs ys] Fixpoint my_rev {A: Type} (l: list A) : list A := match l with nil => nil x :: xs => rev xs ++ x :: nil [Prop] is the type we give to propositions. [Prop] basically works the same as [Type]. In fact, its type is [Type]: Check Prop. Prop : Type The difference is that Coq ensures our programs never depend on inputs whose type is in [Prop]. This helps when we extract programs: we can ensure that all [Prop] related computations are only done at compile time and that our extracted programs never compute over data whose type is in Prop. [mytrue] is a proposition. It has a single constructor, [I], which takes no arguments. This means we can always produce a value of type [mytrue] by just using the [I] constructor. In Coq, we say that a proposition [P] is true if we can produce some term [t] that has type [P]. That is, [P] is true if there exists [t : P]. Inductive mytrue : Prop := I : mytrue. Lemma foo : mytrue. We use the constructor tactic to ask Coq to find a constructor that satisfies the goal. Given a proof of [myfalse], we can prove _anything_. Lemma bogus: False > 1 = 2. Inversion performs case analysis on a hypothesis. Suppose our goal is [G] and we ask Coq to do inversion on hypothesis [H : T]. For each constructor [C] of [T] that could have produced [H], we get a new subgoal requiring us to prove [G] under the assumption that [H = C x1 x2...] for some arguments [x1 x2...] to [C]. Often it will be the case that some constructors of [T] could _not_ have produced [H]. Coq will automatically dispatch those subgoals for us which greatly simplifies proofs. This is the primary difference between [destruct] and [inversion]. For [False] (the builtin equivalent to myfalse), there are 0 constructors, so when we perform inversion, we end up with 0 subgoals and the proof is done! When we write a definition using "Lemma" or "Theorem", what we re actually doing is giving a type [T] and then using tactics to construct a term of type [T]. So far, we generally only do this for types whose type is in [Prop], but we can do it for "normal" types too: Lemma foo : Type. exact bool. exact (list nat). exact nat. Having a contradiction in a hypothesis will let us prove any goal. Monday October 10, 2016 lec03/ 1/7

Oct 05, 16 8:02 Page 3/14 Lemma also_bogus: 1 = 2 > False. [discriminate] is a tactic that looks for mismatching constructors in a hypothesis and uses that contradiction to prove any goal. It is a less general version of the [congruence] tactic we saw in lecture last time. In Coq, there are often many tactics that can solve a particular goal. Sometimes we will use a less general tactic because it can help a reader understand our proof and will usually be faster. Under the hood, [1] looks like [S 0] and [2] looks like [S (S 0)]. [discriminate] will peel off one [S], to get [0 = S 0]. Since [0] and [S] are different constructors of an inductive type (where all constructors are _distinct_) they are not equal, and Coq can use the contradiction to complete our proof. discriminate. Oct 05, 16 8:02 Page 4/14 Inductive expr : Type := constant expressions, like [3] or [0] Eint : Z > expr program variables, like ["x"] or ["foo"] Evar : string > expr adding expressions, [e1 + e2] Eadd : expr > expr > expr multiplying expressions, [e1 * e2] Emul : expr > expr > expr comparing expressions, [e1 <= e2] Elte : expr > expr > expr. On paper, we would typically write this type down using a "BNF grammar" as: expr ::= Z Var expr + expr expr * expr expr <= expr Note that even equality is defined, not builtin. Print eq. Here s [yo], another definition of an empty type. Inductive yo : Prop := yolo : yo > yo. We will have to do a little more work to show that [yo] is empty though. Lemma yoyo: yo > False. well, that didn t work induction H. assumption. but that did! Negation in Coq is encoded in the [not] type. It sort of works like our [yoyo] proof above. Print not. ** Expression Syntax Use String and Z notations. Open Scope string_scope. Open Scope Z_scope. Now let s build a programming language. We can define the syntax of a language as an inductive datatype. Coq provides mechanisms to define your own notation which we can use to get "concrete syntax". Feel free to ignore most of this, especially the "level" and "associativity" stuff. Coercion Eint : Z > > expr. Coercion Evar : string > > expr. Notation "X [+] Y" := (Eadd X Y) (at level 83, left associativity). Notation "X [*] Y" := (Emul X Y) (at level 82, left associativity). Notation "X [<=] Y" := (Elte X Y) (at level 84, no associativity). Check (1 [+] 2). Check ("x" [+] 2). Check ("x" [+] 2 [<=] "y"). Parsing is a classic CS topic, but won t say much more about it in this course. Parsing is still a rich and active research topic, and there are many decent tools out there to help practioners build good parsers. Note that all we ve done so far is define the _syntax_ of expressions in our language. We have said NOTHING about what these expressions _mean_. In upcoming lectures we will spend some time studying how we can describe the meanings of programs by giving _semantics_ for our programming languages. To make this clear, note that operations like addition and multiplication are NOT commutative in syntax. They will only be commutative in the meaning of expressions later. Monday October 10, 2016 lec03/ 2/7

Oct 05, 16 8:02 Page 5/14 Lemma add_comm_bogus : ( Eadd e1 e2 = Eadd e2 e1) > False. The [specialize] tactic gives concrete arguments to a forall quantified hypothesis. specialize (H 0 1). inversion is smart Although we have not yet defined what programs mean, we can write some functions to analyze their syntax. Here we simply count the number of [Eint] subexpressions in a given expression. Fixpoint nconsts (e: expr) : nat := Eint _ => 1 same as [S O] Evar _ => 0 same as [O] Eadd e1 e2 => nconsts e1 + nconsts e2 same as [plus (nconsts e1) (nconsts e2)] Emul e1 e2 => nconsts e1 + nconsts e2 Elte e1 e2 => nconsts e1 + nconsts e2 We can also use existential quantifiers in Coq. To prove an existential, you must provide a _witness_, that is, a concrete example of the type you re existentially quantifying. Lemma expr_w_3_consts: exists e, nconsts e = 3%nat. Here we give a concrete example. exists (3 [+] 2 [+] 1). Now we have to show that the example satisfies the property simpl. reflexivity. Compute the size of an expression. Fixpoint esize (e: expr) : nat := Eint _ Evar _ => 1 Eadd e1 e2 Emul e1 e2 Elte e1 e2 => esize e1 + esize e2 Notice how we grouped similar cases together in the definition of [esize]. This is just sugar, you can see the full definition with: Oct 05, 16 8:02 Page 6/14 Print esize. esize = fix esize (e : expr) : nat := Eint _ => 1%nat Evar _ => 1%nat e1 [+] e2 => (esize e1 + esize e2)%nat e1 [*] e2 => (esize e1 + esize e2)%nat e1 [<=] e2 => (esize e1 + esize e2)%nat end : expr > nat We can use our analyses to prove properties of the syntax of programs. For example, always have at least as many nodes in the AST as constants. Lemma nconsts_le_size: (nconsts e <= esize e)%nat. + simpl. auto. The [auto] tactic will solve many simple goals, including those that reflexivity would solve. [auto] also has the property that it will never fail. If it cannot solve your goal, then it just does nothing. This will be particularly useful when we start chaining together sequences of tactics to operate simultaneously over multiple subgoals. + simpl. auto. The [omega] will solve many arithemetic goals. Unlike [auto], [omega] will fail if it cannot solve your goal. + simpl. omega. + simpl. omega. + simpl. omega. that proof had a lot of copy pasta :( Lemma nconsts_le_size : (nconsts e <= esize e)%nat. Here we see our first "tactic combinator", the powerful semicolon ";". For any tactics [a] and [b], [a; b] runs [a] on the goal and then runs [b] on all of the subgoals generate by [a]. We can chain tactics toghether in this way to make shorter, more automated proofs. Monday October 10, 2016 lec03/ 3/7

Oct 05, 16 8:02 Page 7/14 In the case of this lemma, we d like to: do induction, then on every resulting subgoal do simpl, then on every resulting subgoal do auto, then on every resulting subgoal do omega induction e; simpl; auto; omega. Note that after the [auto], only the Eadd, Emul, and Elte subgoals remain, but it s hard to tell since the proof does not "pause". Notice how sometime we have to use the scope specifier "%nat" so that Coq knows we want the [nat] version of some notation instead of the [Z] version. To figure out where a notation is coming from, you can use the [Locate] command: Locate "<=". This generates a lot of output. In this file we really only care about the [nat] and [Z] entries: "x <= y" := Z.le x y : Z_scope (default interpretation) "n <= m" := le n m : nat_scope We can also print the definition of [le]: Print le. Inductive le (n : nat) : nat > Prop := le_n : (n <= n)%nat le_s : forall m : nat, (n <= m)%nat > (n <= S m)%nat [le] is a relation defined as an "inductive predicate". We give rules for when the relation holds: (1) all nats are less than or equal to themselves and (2) if n <= m, then also n <= S m. All proofs of [le] are built up from just these two constructors! Oct 05, 16 8:02 Page 8/14 Inductive has_const : expr > Prop := hc_in : forall c, has_const (Eint c) hc_add_l : has_const e1 > has_const (Eadd e1 e2) hc_add_r : has_const e2 > has_const (Eadd e1 e2) hc_mul_l : has_const e1 > has_const (Emul e1 e2) hc_mul_r : has_const e2 > has_const (Emul e1 e2) hc_cmp_l : has_const e1 > has_const (Elte e1 e2) hc_cmp_r : has_const e2 > has_const (Elte e1 e2). Similarly, we can define a relation that holds on expressions that contain a variable. Inductive has_var : expr > Prop := hv_var : forall s, has_var (Evar s) hv_add_l : has_var e1 > has_var (Eadd e1 e2) hv_add_r : has_var e2 > has_var (Eadd e1 e2) hv_mul_l : has_var e1 > has_var (Emul e1 e2) hv_mul_r : has_var e2 > has_var (Emul e1 e2) hv_cmp_l : has_var e1 > has_var (Elte e1 e2) hv_cmp_r : has_var e2 > has_var (Elte e1 e2). We can define our own relations to encode properties of expressions. In the [has_const] inductive predicate below, each constructor corresponds to one way you could prove that an expression has a constant. We can also write boolean functions that check the same properties. Note that [orb] is disjuction over booleans: Print orb. Monday October 10, 2016 lec03/ 4/7

Oct 05, 16 8:02 Page 9/14 Fixpoint hasconst (e: expr) : bool := Eint _ => true Evar _ => false Eadd e1 e2 => orb (hasconst e1) (hasconst e2) Emul e1 e2 => orb (hasconst e1) (hasconst e2) Elte e1 e2 => orb (hasconst e1) (hasconst e2) We can write that a little more compactly using the " " notation for [orb] provided by the Bool library. Fixpoint hasvar (e: expr) : bool := Eint _ => false Evar _ => true Eadd e1 e2 => hasvar e1 hasvar e2 Emul e1 e2 => hasvar e1 hasvar e2 Elte e1 e2 => hasvar e1 hasvar e2 That looks way easier! However, as the quarter progresses, we ll see that sometime defining a property as an inductive relation is more convenient. We can prove that our relational and functional versions agree. This shows that the [hasconst] _function_ is COMPLETE with respect to the relation [has_const]. Thus, anything that satisfies the relation evaluates to "true" under the function [hasconst]. Lemma has_const_hasconst: has_const e > hasconst e = true. + simpl. reflexivity. + simpl. uh oh, trying to prove something false! it s OK though because we have a bogus hyp! inversion lets us do case analysis on how a hypothesis of an inductive type may have been built. In this case, there is no way to build a value of type "has_const (Var s)", so we complete the proof of this subgoal for all zero ways of building such a value + here we use inversion to consider how a value of type "has_const (Add e1 e2)" could have been built built with hc_add_l subst. subst rewrites all equalities it can apply IHe1 in H1. simpl. remember notation " " is same as orb rewrite H1. simpl. reflexivity. Oct 05, 16 8:02 Page 10/14 built with hc_add_r subst. apply IHe2 in H1. simpl. rewrite H1. use fact that orb is commutative rewrite orb_comm. you can find this by turning on auto completion or using a search query SearchAbout orb. simpl. reflexivity. + Mul case is similar inversion H; simpl; subst. apply IHe1 in H1; rewrite H1; auto. apply IHe2 in H1; rewrite H1; rewrite orb_comm; auto. + Lte case is similar inversion H; simpl; subst. apply IHe1 in H1; rewrite H1; auto. apply IHe2 in H1; rewrite H1; rewrite orb_comm; auto. Now for the other direction. Here we ll prove that the [hasconst] _function_ is SOUND with respect to the relation. That is, if [hasconst] produces true, then there is some proof of the inductive relation [has_const]. Lemma hasconst_has_const: hasconst e = true > has_const e. + simpl. we can prove this case with a constructor constructor. this uses hc_const + Uh oh, no constructor for has_const can possibly produce a value of our goal type! It s OK though because we have a bogus hypothesis. simpl in H. discriminate. + now do Add case simpl in H. either e1 or e2 had a Const apply orb_true_iff in H. consider cases for H destruct H. e1 had a Const apply hc_add_l. apply IHe1. assumption. e2 had a Const apply hc_add_r. apply IHe2. assumption. + Mul case is similar simpl in H; apply orb_true_iff in H; destruct H. constructor will just use hc_mul_l constructor. apply IHe1. assumption. constructor will screw up and try hc_mul_l again! constructor is rather dim constructor. OOPS! Undo. Monday October 10, 2016 lec03/ 5/7

Oct 05, 16 8:02 Page 11/14 apply hc_mul_r. apply IHe2. assumption. + Lte case is similar simpl in H; apply orb_true_iff in H; destruct H. constructor; auto. apply hc_cmp_r; auto. we can stitch these two lemmas together Lemma has_const_iff_hasconst: has_const e < > hasconst e = true. split. + > apply has_const_hasconst. + < apply hasconst_has_const. Notice all that work was only for the "true" cases! We can prove analogous facts for the "false" cases too. Here we will prove the "false" cases directly. However, note that you could use [has_const_iff_hasconst] to get a much simpler proof. Lemma not_has_const_hasconst: ~ has_const e > hasconst e = false. unfold not. + simpl. uh oh, trying to prove something bogus better exploit a bogus hypothesis exfalso. proof by contradiction apply H. constructor. + simpl. reflexivity. + simpl. apply orb_false_iff. prove conjunction by proving left and right split. apply IHe1. intro. apply H. apply hc_add_l. assumption. apply IHe2. intro. apply H. apply hc_add_r. assumption. + Mul case is similar simpl; apply orb_false_iff. split. apply IHe1; intro. apply H. apply hc_mul_l. assumption. apply IHe2; intro. apply H. apply hc_mul_r. assumption. + Lte case is similar simpl; apply orb_false_iff. split. apply IHe1; intro. apply H. apply hc_cmp_l. assumption. apply IHe2; intro. apply H. apply hc_cmp_r. assumption. Here is a more direct proof based on the iff we proved for the true case. Oct 05, 16 8:02 Page 12/14 Lemma not_has_const_hasconst : ~ has_const e > hasconst e = false. do case analysis on hasconst e eqn:? remembers the result in a hypothesis destruct (hasconst e) eqn:?. rewrite < has_const_iff_hasconst in Heqb. now we have hasconst e = true in our hypothesis We have a contradiction in our hypotheses discriminate won t work this time though unfold not in H. apply H in Heqb. inversion Heqb. reflexivity. For the other case, this is easy Now the other direction of the false case Lemma false_hasconst_hasconst: hasconst e = false > ~ has_const e. unfold not. induction e; crunch down everything in subgoals simpl in *. + discriminate. + inversion H0. + apply orb_false_iff in H. get both proofs out of a conjunction by destructing it destruct H. case analysis on H0 DISCUSS: how do we know to do this? inversion H0. subst. auto. auto will chain things for us subst. auto. + Mul case similar apply orb_false_iff in H; destruct H. inversion H0; subst; auto. + Lte case similar apply orb_false_iff in H; destruct H. inversion H0; subst; auto. Since we ve proven the iff for the true case We can use it to prove the false case This is the same lemma as above, but using our previous results Lemma false_hasconst_hasconst : hasconst e = false > ~ has_const e. ~ X is just X > False unfold not. rewrite has_const_iff_hasconst in H0. rewrite H in H0. discriminate. We can also do all the same Monday October 10, 2016 lec03/ 6/7

Oct 05, 16 8:02 Page 13/14 sorts of proofs for has_var and hasvar Lemma has_var_hasvar: has_var e > hasvar e = true. TODO: try this without copying from above Admitted. Lemma hasvar_has_var: hasvar e = true > has_var e. TODO: try this without copying from above Admitted. Lemma has_var_iff_hasvar: has_var e < > hasvar e = true. TODO: try this without copying from above Admitted. we can also prove things about expressions Lemma expr_bottoms_out: has_const e \/ has_var e. + prove left side of disjunction left. constructor. + prove right side of disjunction right. constructor. + case analysis on IHe1 destruct IHe1. left. constructor. assumption. right. constructor. assumption. + Mul case similar destruct IHe1. left. constructor. assumption. right. constructor. assumption. + Cmp case similar destruct IHe1. left. constructor. assumption. right. constructor. assumption. Oct 05, 16 8:02 Page 14/14 or even better Lemma has_const_hasconst : has_const e > hasconst e = true. induction H; simpl; auto; rewrite orb_true_iff; auto. Lemma not_has_const_hasconst : ~ has_const e > hasconst e = false. unfold not; destruct (hasconst e) eqn:?. exfalso. apply H. apply hasconst_has_const; auto. reflexivity. Lemma false_hasconst_hasconst : hasconst e = false > ~ has_const e. unfold not; destruct (hasconst e) eqn:?. discriminate. rewrite has_const_hasconst in Heqb. NOTE: we got another subgoal! * discriminate. * assumption. In general: Relational defns are nice when you want to use inversion. Functional defns are nice when you want to use simpl. we could have gotten some of the has_const lemmas by being a little clever! (but then we wouldn t have learned as many tactics ;) ) Lemma has_const_hasconst : has_const e > hasconst e = true. induction H; simpl; auto. Monday October 10, 2016 lec03/ 7/7