theory tut3_solutions imports Main begin (* Solutions using explicit instantiation and avoiding introduction of meta-variables *) lemma one: "(\ x. P x \ Q) \ ((\ x. P x) \ Q)" apply (rule impI) apply (rule impI) apply (erule exE) apply (erule_tac x="x" in allE) apply (erule mp) apply assumption done lemma two: "\(\ x. P x) \ \ x. \P x" apply (rule allI) apply (rule notI) apply (erule notE) apply (rule_tac x="x" in exI) by assumption lemma three: "\(\ x. P x) \ \ x. \P x" apply (rule ccontr) apply (erule notE) apply (rule allI) apply (rule ccontr) apply (erule notE) apply (rule_tac x="x" in exI) by assumption (* Solutions exploiting meta-variables that avoid explicit introduction of instantiating terms. Unification calculates appropriate instantiations of the meta-variables automatically. These solutions are presented for your interest. The course does not require you to understand how they work. *) (* Observe here in lemma one_a: - After the erule allE, the meta-variable introduced has a function type and is applied to the variable x, bound by a meta-forall quantifier. Why? Well isabelle instantiates meta-variables using capture-avoiding substitution. Here the meta-variable introduced can be a function that then makes use of the variable x. - In the `apply assumption' step, Isabelle uses Higher-order unification to unify terms ?f x and x, yielding the substitution [(\y.y) / ?f]. (\y is `lambda y'). Higher-order unification has the lambda calculus beta rule built in, so substituting \y.y for ?f yields `(\y.y) x' which is equal by the beta-rule to x. *) lemma one_a: "(\ x. P x \ Q) \ ((\ x. P x) \ Q)" apply (rule impI) apply (rule impI) apply (erule exE) apply (erule allE) apply (erule mp) apply assumption done lemma two_a: "\(\ x. P x) \ \ x. \P x" apply (rule allI) apply (rule notI) apply (erule notE) apply (rule exI) by assumption lemma three_a: "\(\ x. P x) \ \ x. \P x" apply (rule ccontr) apply (erule notE) apply (rule allI) apply (rule ccontr) apply (erule notE) apply (rule exI) by assumption end