Define `curry` in Lean Theorem Prover - theorem-proving

I am reading the official tutorial for Lean 3. I am stuck on the second exercise in Chapter 2:
complete the following definitions, which “curry” and “uncurry” a function.
def curry (α β γ : Type*) (f : α × β → γ) : α → β → γ := sorry
def uncurry (α β γ : Type*) (f : α → β → γ) : α × β → γ := sorry
My current attempt is
def curry (α β γ : Type*) (f : α × β → γ) (x : α) (y : β) : γ := f (x, y)
This is unsatisfying since I modified the type from the exercise rather than just replacing "sorry" with some code. What is a better approach to take while keeping the type the same? I'd appreciate some tips to point me in the right direction rather than a complete solution.

Related

exp function in Coq doesn't appear to terminate

I'm new to Coq. I've been working through Pierce's Logical Foundations. My interest is a bit out-of-scope of this excellent text as I want to get up-and-running with some math problems.
One of the first things I tried with reals (the R type) was this:
Compute exp 1.
Which sent Coq into an infinite loop. Can this be computed? Is the definition of exp only for proofs?
Doing:
Print exp.
Print proj1_sig.
Print exist_exp.
Yields:
exp = fun x : R => proj1_sig (exist_exp x)
: R -> R
Argument scope is [R_scope]
proj1_sig =
fun (A : Type) (P : A -> Prop) (e : {x : A | P x}) => let (a, _) := e in a
: forall (A : Type) (P : A -> Prop), {x : A | P x} -> A
Arguments A, P are implicit
Argument scopes are [type_scope function_scope _]
exist_exp =
fun x : R =>
(fun H : {l : R | infinite_sum (fun n : nat => (/ INR (fact n) * x ^ n)%R) l}
=> H)
(Alembert_C3 (fun n : nat => (/ INR (fact n))%R) x exp_cof_no_R0
Alembert_exp)
: forall x : R, {l : R | exp_in x l}
Good grief!! How can I learn all of this?!
The thing to understand is that compute asks Coq to put exp 1 into a form that is normal with respect to the rules of its lambda-calculus. So, Coq is not entering an infinite loop. It is just that the normal form of exp 1 is so large that Coq takes a very long time to compute it (and display it).
In practice, no one is ever interested in the normal form of exp 1. So, what are you trying to compute? If you are only interested in computing guaranteed approximations of exp 1, I suggest looking at the CoRN or CoqInterval libraries.
If you just want to see the definition of exp, then your Print approach is fine. It shows that exp is defined as the limit of the traditional power series. It looks a bit ugly, because the definition also embeds the proof that it is convergent for any real number.

Lean : Proof that \ not p \to (p \ to q) or similar false \to p

I am new at lean - prover and I am trying to solve the examples on the online tutorial.
I am stuck at this example and I need to prove that "false implies q" or something like that.
My code is :
variables p q : Prop
example : ¬ p → (p → q) :=
assume h : ¬ p,
assume hp : p,
--have hnpq : ¬ p ∨ q, from or.inl h,
have hf : false, from h hp,
--show q, from hf
sorry
I do not think that defining hnpq can help because this proof is part of the (¬ p ∨ q) → (p → q).
In set theory I think that false implies everything.
Any suggestions or thoughts?

How can I use agda2-mode to generate patterns when I expect to see an absurd pattern?

For example, we're proving 2 + 2 != 5:
data _+_≡_ : ℕ → ℕ → ℕ → Set where
znn : ∀ {n} → zero + n ≡ n
sns : ∀ {m n k} → m + n ≡ k → suc m + n ≡ suc k
And I can manually prove it:
2+2≠5 : 2 + 2 ≡ 5 → ⊥
2+2≠5 (sns (sns ()))
But I want the pattern (sns (sns ())) to be generated (just like filling a hole). Are there any ways to achieve that?
I am using Emacs 25 with agda2-mode.
Ok, so let's say you start from this configuration:
2+2≠5 : 2 + 2 ≡ 5 → ⊥
2+2≠5 h = {!!}
In this case you can use emacs' keyboard macros because the sub-term generated by matching on h will also be named h. So using:
<f3> (start recording the macro)
C-c C-f (move to the hole)
C-c C-c h RET (match on h)
<f4> (record the macro)
you've recorded the action of "moving to the first goal an matching on h". You can now keep pressing <f4> until you reach an absurd case.

Abstracting over the term ... leads to a term ... which is ill-typed

Here is what I am trying to prove:
A : Type
i : nat
index_f : nat → nat
n : nat
ip : n < i
partial_index_f : nat → option nat
L : partial_index_f (index_f n) ≡ Some n
V : ∀ i0 : nat, i0 < i → option A
l : ∀ z : nat, partial_index_f (index_f n) ≡ Some z → z < i
============================
V n ip
≡ match
partial_index_f (index_f n) as fn
return (partial_index_f (index_f n) ≡ fn → option A)
with
| Some z => λ p : partial_index_f (index_f n) ≡ Some z, V z (l z p)
| None => λ _ : partial_index_f (index_f n) ≡ None, None
end eq_refl
The obvious next step is either rewrite L or destruct (partial_index_f (index_f n). Trying to applying rewrite gives me an error:
Error: Abstracting over the term "partial_index_f (index_f n)"
leads to a term
"λ o : option nat,
V n ip
≡ match o as fn return (o ≡ fn → option A) with
| Some z => λ p : o ≡ Some z, V z (l z p)
| None => λ _ : o ≡ None, None
end eq_refl" which is ill-typed.
I do not understand what is causing this problem. I also would like to understand how I can deal with it in general.
I was able to prove it using the following steps, but I am not sure this is the best way:
destruct (partial_index_f (index_f n)).
inversion L.
generalize (l n0 eq_refl).
intros. subst n0.
replace l0 with ip by apply proof_irrelevance.
reflexivity.
congruence.
In Coq's theory, when you perform a rewrite with an equation, you have to generalize over the side of the equation that you want to replace. In your case, you want to replace partial_index_f (index_f n), so Coq tries to generalize that, as you can tell from the error message you got.
Now, if your goal contains something whose type mentions the thing that you want to replace, you might run into trouble, because this generalization might make the goal become ill-typed. (Notice that that type does not exactly occur in the goal, hence Coq does not try to deal with it like it does when something occurs in the goal.) Going back to your case, your l function has type ∀ z : nat, partial_index_f (index_f n) ≡ Some z → z < i, which mentions partial_index_f (index_f n), the term you want to replace. In the first branch of your match, you apply this function to the o = Some z hypothesis that you abstracted over. On the original goal, o was the thing you wanted to replace, but when Coq tries to generalize, the two do not match anymore, hence the error message.
I can't try to fix the problem on my own, but you can solve issues like this usually by generalizing over the term in your context that mentions the term you are replacing, because then its type will show in the goal, associated to a universally quantified variable. This might not help if your term is defined globally and you need it to have a certain shape after the rewrite in order to be able to perform additional reasoning steps, in which case you will probably have to generalize over the lemmas that you need as well.

Do agda programs necessarily terminate?

It has been stated a few places that all agda programs terminate. However I can construct a function like this:
stall : ∀ n → ℕ
stall 0 = 0
stall x = stall x
The syntax highlighter doesn't seem to like it, but there are no compilation errors.
Computing the normal form of stall 0 results in 0. Computing the result of stall 1 causes Emacs to hang in what looks a lot like a non-terminating loop.
Is this a bug? Or can Agda sometimes run forever? Or is something more subtle going on?
In fact, there are compilation errors. The agda executable finds an error and passes that information to agda-mode in Emacs, which in turn does the syntax highlighting to let you know there was an error. We can take a look at what happens if we use agda directly. Here's the file I'm using:
module C1 where
open import Data.Nat
loop : ℕ → ℕ
loop 0 = 0
loop x = loop x
Now, we call agda -i../lib-0.7/src -i. C1.agda (don't mind the -i parameters, they just let the executable know where to look for the standard library) and we get the error:
Termination checking failed for the following functions:
loop
Problematic calls:
loop x
(at D:\Agda\tc\C1.agda:7,10-14)
This is indeed compilation error. Such errors prevent us from importing this module from other modules or compiling it. For example, if we add these lines to the file above:
open import IO
main = run (putStrLn "")
And compile the module using C-c C-x C-c, agda-mode complains:
You can only compile modules without unsolved metavariables
or termination checking problems.
Other kinds of compilation errors include type checking problems:
module C2 where
open import Data.Bool
open import Data.Nat
type-error : ℕ → Bool
type-error n = n
__________________________
D:\Agda\tc\C2.agda:7,16-17
ℕ !=< Bool of type Set
when checking that the expression n has type Bool
Failed positivity check:
module C3 where
data Positivity : Set where
bad : (Positivity → Positivity) → Positivity
__________________________
D:\Agda\tc\C3.agda:3,6-16
Positivity is not strictly positive, because it occurs to the left
of an arrow in the type of the constructor bad in the definition of
Positivity.
Or unsolved metavariables:
module C4 where
open import Data.Nat
meta : ∀ {a} → ℕ
meta = 0
__________________________
Unsolved metas at the following locations:
D:\Agda\tc\C4.agda:5,11-12
Now, you rightly noticed that some errors are "dead ends", while others let you carry on writing your program. That's because some errors are worse than others. For example, if you get unsolved metavariable, chances are that you'll be able to just fill in the missing information and everything will be okay.
As for hanging the compiler: checking or compiling a module shouldn't cause agda to loop. Let's try to force the type checker to loop. We'll add more stuff into the module C1:
data _≡_ {a} {A : Set a} (x : A) : A → Set a where
refl : x ≡ x
test : loop 1 ≡ 1
test = refl
Now, to check that refl is correct expression of that type, agda has to evaluate loop 1. However, since the termination check failed, agda will not unroll loop (and end up in an infinite loop).
However, C-c C-n really forces agda to try to evaluate the expression (you basically tell it "I know what I'm doing"), so naturally you get into an infinite loop.
Incidentally, you can make agda loop if you disable the termination check:
{-# NO_TERMINATION_CHECK #-}
loop : ℕ → ℕ
loop 0 = 0
loop x = loop x
data _≡_ {a} {A : Set a} (x : A) : A → Set a where
refl : x ≡ x
test : loop 1 ≡ 1
test = refl
Which ends up in:
stack overflow
As a rule of thumb: if you can make agda loop by checking (or compiling) a module without using any compiler pragmas, then this is indeed a bug and should be reported on the bug tracker. That being said, there are few ways to make non-terminating program if you are willing to use compiler pragmas. We've already seen {-# NO_TERMINATION_CHECK #-}, here are some other ways:
{-# OPTIONS --no-positivity-check #-}
module Boom where
data Bad (A : Set) : Set where
bad : (Bad A → A) → Bad A
unBad : {A : Set} → Bad A → Bad A → A
unBad (bad f) = f
fix : {A : Set} → (A → A) → A
fix f = (λ x → f (unBad x x)) (bad λ x → f (unBad x x))
loop : {A : Set} → A
loop = fix λ x → x
This one relies on a data type which is not strictly positive. Or we could force agda to accept Set : Set (that is, the type of Set is Set itself) and reconstruct Russell's paradox:
{-# OPTIONS --type-in-type #-}
module Boom where
open import Data.Empty
open import Data.Product
open import Relation.Binary.PropositionalEquality
data M : Set where
m : (I : Set) → (I → M) → M
_∈_ : M → M → Set
a ∈ m I f = Σ I λ i → a ≡ f i
_∉_ : M → M → Set
a ∉ b = (a ∈ b) → ⊥
-- Set of all sets that are not members of themselves.
R : M
R = m (Σ M λ a → a ∉ a) proj₁
-- If a set belongs to R, it does not contain itself.
lem₁ : ∀ {X} → X ∈ R → X ∉ X
lem₁ ((Y , Y∉Y) , refl) = Y∉Y
-- If a set does not contain itself, then it is in R.
lem₂ : ∀ {X} → X ∉ X → X ∈ R
lem₂ X∉X = (_ , X∉X) , refl
-- R does not contain itself.
lem₃ : R ∉ R
lem₃ R∈R = lem₁ R∈R R∈R
-- But R also contains itself - a paradox.
lem₄ : R ∈ R
lem₄ = lem₂ lem₃
loop : {A : Set} → A
loop = ⊥-elim (lem₃ lem₄)
(source). We could also write a variant of Girard's paradox, simplified by A.J.C. Hurkens:
{-# OPTIONS --type-in-type #-}
module Boom where
⊥ = ∀ p → p
¬_ = λ A → A → ⊥
℘_ = λ A → A → Set
℘℘_ = λ A → ℘ ℘ A
U = (X : Set) → (℘℘ X → X) → ℘℘ X
τ : ℘℘ U → U
τ t = λ (X : Set) (f : ℘℘ X → X) (p : ℘ X) → t λ (x : U) → p (f (x X f))
σ : U → ℘℘ U
σ s = s U λ (t : ℘℘ U) → τ t
τσ : U → U
τσ x = τ (σ x)
Δ = λ (y : U) → ¬ (∀ (p : ℘ U) → σ y p → p (τσ y))
Ω = τ λ (p : ℘ U) → ∀ (x : U) → σ x p → p x
loop : (A : Set) → A
loop = (λ (₀ : ∀ (p : ℘ U) → (∀ (x : U) → σ x p → p x) → p Ω) →
(₀ Δ λ (x : U) (₂ : σ x Δ) (₃ : ∀ (p : ℘ U) → σ x p → p (τσ x)) →
(₃ Δ ₂ λ (p : ℘ U) → (₃ λ (y : U) → p (τσ y)))) λ (p : ℘ U) →
₀ λ (y : U) → p (τσ y)) λ (p : ℘ U) (₁ : ∀ (x : U) → σ x p → p x) →
₁ Ω λ (x : U) → ₁ (τσ x)
This one is a real mess, though. But it has a nice property that it uses only dependent functions. Strangely, it doesn't even get past type checking and causes agda to loop. Splitting the whole loop term into two helps.
The syntax highlighting you are seeing is a compile error. The termination checker's effect is to highlight non-terminating functions in a kind of pink-orange color ("salmon"). You may notice that a module containing such an error cannot be imported from other modules. It can also not be compiled down to Haskell.
So yes, Agda programs always terminate and this is not a bug.