Lean 4 'unknown identifier Proof' - proof

I have been experiencing an issue when using Lean 4.
I ran into it while working my way through the docs, in the Propositions and Proofs section. Under Propositions as Types, the docs introduce the Proof Type:
We could then introduce, for each element p : Prop, another type Proof p, for the type of proofs of p.
Below, it shows a code snippet checking for the type of Proof, which returns Proof : Prop → Type:
#check Proof -- Proof : Prop → Type
When I try running this snippet, I get the following error:
example.lean:3:7: error: unknown identifier 'Proof'
implying that lean can not find the Proof type. This is my problem, how do I get Lean to recognize Proof?
Thanks!

There is no such type called Proof. The docs mention it as an example of how Lean could have been implemented, but go on to explain why it was not implemented like that.

"Theorem Proving in Lean 4" is still under construction (indeed lean 4 itself is still changing rapidly), so you will probably find many issues in it. In this case, however, I believe the issue is that it is speaking hypothetically about one way things could be set up that is not in fact the way it is done in lean.
Here's one way to make those code blocks actually compile:
namespace TPIL
axiom Prop' : Type
axiom And : Prop' → Prop' → Prop'
axiom Or : Prop' → Prop' → Prop'
axiom Not : Prop' → Prop'
axiom Implies : Prop' → Prop' → Prop'
axiom Proof : Prop' → Type
variable (p q r : Prop')
#check And p q -- Prop'
#check Or (And p q) r -- Prop'
#check Implies (And p q) (And q p) -- Prop'
#check Proof -- Proof : Prop' → Type
axiom and_comm (p q : Prop') : Proof (Implies (And p q) (And q p))
variable (p q : Prop')
#check and_comm p q -- Proof (Implies (And p q) (And q p))
axiom modus_ponens : (p q : Prop') → Proof (Implies p q) → Proof p → Proof q
axiom implies_intro : (p q : Prop') → (Proof p → Proof q) → Proof (Implies p q)
You have to use Prop' or «Prop» since Prop is a keyword, though.

Related

Looking for explanation about implicit function type vs explicit function type

Considering the following agda module signature:
module EqList {a ℓ} {A : Set a} {_≈_ : Rel A ℓ} (eq≈ : IsEquivalence _≈_) where
We can define the membership in a list, the list inclusion and the list equivalence:
_∈_ : REL A (List A) _
_∈_ x = Any (x ≈_)
_⊑_ : Rel (List A) _
_⊑_ = _⊆_ on flip _∈_
_≋_ : Rel (List A) _
_≋_ = _⊑_ -[ _×_ ]- flip _⊑_
We can then proceed to prove that this last relation is indeed an equivalence relation:
isEq≋ : IsEquivalence _≋_
isEq≋ = record {
refl = id , id ;
sym = swap ;
trans = zip (λ f g → g ∘ f) λ f g → f ∘ g }
The proof of transitivity is what makes my question arise. The previous definition is accepted by Agda while the following is rejected:
trans = zip (flip _∘_) _∘_
The error is as follows:
({x : A} → Any (_≈_ x) i → Any (_≈_ x) j) !=
((x : A) → Any (_≈_ x) j) because one is an implicit function type
and the other is an explicit function type
when checking that the expression _∘_ has type
(x : j ⊑ k) (y : i ⊑ j) → i ⊑ k
While this error feels weird, because both proofs should be equivalent (replacing the expression f by the expression λ x → f x should always yield the same result) I can somewhat understand why it behaves this way : there is intern trouble as to how to instantiate the various implicit arguments of _∘_. But this explanation is only intuitive and not very conclusive, so my question is the following:
Can someone explain in details why the typechecker succeeds in the first case and not in the second ?
As a side note, here is the header of the module, in order for this example to be self contained:
open import Relation.Binary.Core
open import Data.List hiding (zip)
open import Data.List.Any
open import Relation.Unary using (_⊆_)
open import Function
open import Data.Product
As a second side note, I am aware that a similar question has already been answered:
How to get around the implicit vs explicit function type error?
But said answer does not contain any deep explanation about this surprising behavior.

Why does Haskell presume the returned monad type is the same type that is passed as an argument?

Why does this code compile?
--sequence_mine :: Monad m => [m a] -> m [a]
sequence_mine [] = return []
sequence_mine (elt:l) = do
e <- elt
sl <- sequence l
return (e:sl)
Note I intentionally commented out the type declaration here. But the code still compiles and seems to work as expected, even without the type declaration - and this is what surprises me.
To my understanding, ambiguity should arise on this line:
return (e:sl)
The reason is that Haskell shouldn't know which type of monad we are returning. Why does it have to be the same type that we are accepting?
To clarify more. To my understanding, if I don't explicitely put the type declaration analogous to the one I commented out, Haskell should deduce this function has a typing like this:
sequence_mine :: (Monad m1, Monad m2) => [m1 a] -> m2 [a]
Unless I explicitely unify m1 and m2 by calling them both m, there is no reason for Haskell to believe they both refer to the same type! I would suppose.
Yet that is not the case. What am I missing here?
Well, let's look at what the do block desugars to:
sequence_mine (elt:l) = elt >>= \e -> (sequence l) >>= \sl -> return (e:sl)
Recall that the "bind" operator >>= has the type signature (Monad m) => m a -> (a -> m b) -> m b. Note that the monad m here, although arbitrary, must be the same for both of the arguments and the result type.
So if elt has type m a, it's easy to see that the return (e:sl) - which is the output type of the whole expression - must have type m [a], for the same monad m.
To put it another way, each do block only works in the context of a fixed monad.

error message when implementing `((->) r)` monad (type mismatch)

I'm just starting to learn haskell, and I'm trying to implement some common monads as exercises for myself. As I was fiddling with the ((->) r) monad, I implemented this (wrong) definition:
instance Monad ((->) r) where
return x = \_ -> x
m >>= f = \c -> (f . m) c
GHCi complained to me with
• Couldn't match expected type ‘b’ with actual type ‘t -> b’
`b’ is a rigid type variable bound by
the type signature for:
(>>=) :: forall a b. (t -> a) -> (a -> t -> b) -> t -> b
whereas the type should be:
(>>=) :: (t -> a ) -> (a -> t -> b) -> t -> b
Why does my implementation break it? And seemingly, the forall version should give the exact same type, but GHCi thinks otherwise. What's the difference?
My fatal misunderstanding was that I thought the error message meant that my implementation had an incorrect type signature. (I thought that because there was a forall in the type signature.) It turns out that's not the actual error, and my error in the implementation was that I needed to apply another r term to both f and m in my implementation. Thanks to #luqui and #melpomene for pointing it out to me

Appending nil to a dependently typed length indexed vector in Lean

Assume the following definition:
def app {α : Type} : Π{m n : ℕ}, vector α m → vector α n → vector α (n + m)
| 0 _ [] v := by simp [add_zero]; assumption
| (nat.succ _) _ (h :: t) v' := begin apply vector.cons,
exact h,
apply app t v'
end
Do note that (n + m) are flipped in the definition, so as to avoid plugging add_symm into the definition. Also, remember that add / + is defined on rhs in Lean. vector is a hand rolled nil / cons defined length indexed list.
So anyway, first we have a lemma that follows from definition:
theorem nil_app_v {α : Type} : ∀{n : ℕ} (v : vector α n),
v = [] ++ v := assume n v, rfl
Now we have a lemma that doesn't follow from definition, as such I use eq.rec to formulate it.
theorem app_nil_v {α : Type} : ∀{n : ℕ} (v : vector α n),
v = eq.rec (v ++ []) (zero_add n)
Note that eq.rec is just C y → Π {a : X}, y = a → C a.
The idea of a proof is trivial by induction on v. The base case follows immediately from definition, the recursive case should follow immediately from the inductive hypothesis and definition, but I can't convince Lean of this.
begin
intros n v,
induction v,
-- base case
refl,
-- inductive case
end
The inductive hypothesis I get from Lean is a_1 = eq.rec (a_1 ++ vector.nil) (zero_add n_1).
How do I use it with conclusion a :: a_1 = eq.rec (a :: a_1 ++ vector.nil) (zero_add (nat.succ n_1))? I can unfold app to reduce the term a :: a_1 ++ vector.nil to a :: (a_1 ++ vector.nil), and now I am stuck.

Why does Haskell point free version of function result in ambiguous type error?

It turns out that in GHC 7.10, this compiles fine:
mysum xs = foldr (+) 0 xs
But this:
mysum = foldr (+) 0
results in the following error:
No instance for (Foldable t0) arising from a use of ‘foldr’
The type variable ‘t0’ is ambiguous
Relevant bindings include
mysum :: t0 Integer -> Integer (bound at src/Main.hs:37:1)
Note: there are several potential instances:
instance Foldable (Either a) -- Defined in ‘Data.Foldable’
instance Foldable Data.Functor.Identity.Identity
-- Defined in ‘Data.Functor.Identity’
instance Foldable Data.Proxy.Proxy -- Defined in ‘Data.Foldable’
...plus five others
In the expression: foldr (+) 0
In an equation for ‘mysum’: mysum = foldr (+) 0
Why does this happen, and what is the insight that's achieved by understanding this difference? Also, can I give this function a type (that's still generic) to make this error go away?
As usual with cases where making a well-typed function point-free suddenly results in type errors about unfulfilled typeclass constraints, the ultimate cause of this is the monomorphism restriction, enabled by default.
You can solve this by either adding a type signature to mysum:
mysum :: (Foldable f, Num a) => f a -> a
or by turning off the monomorphism restriction:
{-# LANGUAGE NoMonomorphismRestriction #-}