Does lean have syntax for declaration of signatures? - lean

I've looked but haven't found any mechanism described in the documentation which allows you to describe a section by it's signature. For example, in the section below the syntax of def requires the right hand side (here sorry)
section
variable A : Type
def ident : A → A := sorry
end
Is there anything like a signature which would allow you to forward declare the contents of a section? Such as in the following made up syntax.
signature
variable A : Type
def ident : A → A
end
The closest i've come using actual syntax is the following,
which declares the proofs twice, the second time for keeping the proof on the right hand side as short as possible.
section
variables A B : Type
def ident' {A : Type} : A → A := (λ x, x)
def mp' {A B : Type}: (A → B) → A → B := (λ f, λ x, f x)
/- Signature-/
def ident : A → A := ident'
def mp : (A → B) → A → B := mp'
end

No, forward declarations are not allowed in general. Lean, like most other ITPs, relies on the order of declarations for termination checking. Forward declarations would allow you to introduce arbitrary mutual recursion, which Lean 3 only accepts in a clearly delimited context:
mutual def even, odd
with even : nat → bool
| 0 := tt
| (a+1) := odd a
with odd : nat → bool
| 0 := ff
| (a+1) := even a
(from Theorem Proving in Lean)

Related

Default Implementation of Coq typeclass methods

Is there a way you can provide default implementations of Coq typeclass methods like you can in Haskell? I saw no mention of this in the Coq typeclass documentation. If there does not exist such a feature, is there a common pattern for emulating this behavior?
A default implementation can be viewed as a function which constructs the default methods given other provided methods. So you can just define a function.
Class C a :=
{ m1 : a
; m2 : a
}.
(* Construct an instance of C from an implementation of only m1. *)
Definition mkC {a} (m1_ : a) := {| m1 := m1_ ; m2 := m1_ |}.
#[global]
Instance C_nat : C nat := mkC 0.
Another idea is to break the class into single-method classes. Then you can first define instances for the explicitly implemented methods, and then again use functions to obtain default implementations for other methods. By breaking down the class this way, you don't need to explicitly apply the default function to the provided methods.
Class N1 a :=
n1 : a.
Class N2 a :=
n2 : a.
(* Default implementation of N2 using N1 *)
Definition defaultN2 {a} {_ : N1 a} : N2 a := n1 (a := a).
#[global]
Instance N1_nat : N1 nat := 0.
#[global]
Instance N2_nat : N2 nat := defaultN2. (* N1 nat is passed implicitly here *)
I wish that you could do this, but it is not supported.

Why both the typeclass and implicit argument mechanism?

So we can have explicit arguments, denoted by ().
We can also have implicit arguments, denoted by {}.
So far so good.
However, why do we also need the [] notation for type classes specifically?
What is the difference between the following two:
theorem foo {x : Type} : ∀s : inhabited x, x := sorry
theorem foo' {x : Type} [s : inhabited x] : x := sorry
Implicit arguments are inserted automatically by Lean's elaborator. The {x : Type} that appears in both of your definitions is one example of an implicit argument: if you have s : inhabited nat, then you can write foo s, which will elaborate to a term of type nat, because the x argument can be inferred from s.
Type class arguments are another kind of implicit argument. Rather than being inferred from later arguments, the elaborator runs a procedure called type class resolution that will attempt to generate a term of the designated type. (See chapter 10 of https://leanprover.github.io/theorem_proving_in_lean/theorem_proving_in_lean.pdf.) So, your foo' will actually take no arguments at all. If the expected type x can be inferred from context, Lean will look for an instance of inhabited x and insert it:
def foo' {x : Type} [s : inhabited x] : x := default x
instance inh_nat : inhabited nat := ⟨3⟩
#eval (2 : ℕ) + foo' -- 5
Here, Lean infers that x must be nat, and finds and inserts the instance of inhabited nat, so that foo' alone elaborates to a term of type nat.

Coq: set default implicit parameters

Suppose I have a code with a lot of modules and sections. In some of them there are polymorphic definitions.
Module MyModule.
Section MyDefs.
(* Implicit. *)
Context {T: Type}.
Inductive myIndType: Type :=
| C : T -> myIndType.
End MyDefs.
End MyModule.
Module AnotherModule.
Section AnotherSection.
Context {T: Type}.
Variable P: Type -> Prop.
(* ↓↓ ↓↓ - It's pretty annoying. *)
Lemma lemma: P (#myIndType T).
End AnotherSection.
End AnotherModule.
Usually Coq can infer the type, but often I still get typing error. In such cases, you have to explicitly specify the implicit type with #, which spoils the readability.
Cannot infer the implicit parameter _ of _ whose type is "Type".
Is there a way to avoid this? Is it possible to specify something like default parameters, which will be substituted every time Coq cannot guess a type?
You can use a typeclass to implement this notion of default value:
Class Default (A : Type) (a : A) :=
withDefault { value : A }.
Arguments withDefault {_} {_}.
Arguments value {_} {_}.
Instance default (A : Type) (a : A) : Default A a :=
withDefault a.
Definition myNat `{dft : Default nat 3} : nat :=
value dft.
Eval cbv in myNat.
(* = 3 : nat *)
Eval cbv in (#myNat (withDefault 5)).
(* = 5 : nat *)

Mimicking Haskell canonicity (one-instance only) of typeclasses in Agda

Agda's mixiture of records and the instance keyword give us behaviour similar to that of Haskell's typeclasses. Moreover, ignoring the instance keyword, we can have more than one instance for the same type --- something we cannot do in Haskell.
I am at a point where I need Haskell's one-instance only requirement, but in Agda.
Is there an compiler option or some trick/heuristic to enforce this?
Right now the approach I am taking is,
record Yo (n : ℕ) : Set where
field
sem : (some interesting property involving n)
open Yo {{...}}
postulate UniqueYo: ∀ {n} (p q : Yo n) → p ≡ q
However, whenever I actually use UniqueYo the lack of computation leaves my goals littered with things like ...| UniqueYo p p where I'd prefer ...| refl or a full rewrite into normal form instead.
Any help is appreciated!
With newer versions of Agda you could use the Prop universe to get definitional uniqueness of a type:
{-# OPTIONS --prop #-}
module UniquenessUsingProp where
open import Data.Nat.Base
open import Relation.Binary.PropositionalEquality
-- Convert a Set to a Prop. This could be avoided if e.g.
-- we defined > as a Prop (like in the example in the docs
-- linked above)
data Squash {ℓ} (A : Set ℓ) : Prop ℓ where
squash : A → Squash A
-- record Yo (n : ℕ) : Prop where -- Both variants works
record Yo (n : ℕ) : Set where
field
sem : Squash (n + 1 > n * 2)
-- Since `Yo n` is a Prop and not a set, it can't be the
-- direct argument of ≡. This is not a problem since
-- it's definitionally equal anyways.
UniqueYo : ∀ {n} (P : Yo n → Set) (p q : Yo n) → P p ≡ P q
UniqueYo P p q = refl
Another alternative that produces similar results is using proof irrelevant record fields:
module UniqunessUsingProofIrrelevance where
open import Data.Nat.Base
open import Relation.Binary.PropositionalEquality
record Yo (n : ℕ) : Set where
field
.sem : n + 1 > n * 2
open Yo {{...}}
UniqueYo : ∀ {n} (p q : Yo n) → p ≡ q
UniqueYo p q = refl
In both cases, actually using the value in Yo can be difficult, since you need to convince Agda that your code does not depend on the concrete value in sem, e.g. by only using absurd pattern matches on it or by producing values in Prop or respectively, providing it as an argument to irrelevant functions.

Agda: my code doesn't type check (how to get implicit arguments right?)

"checkSimple" gets u, an element of the universe U, and checks if
(nat 1) can be converted to a agda type given u. The result of the conversion is returned.
Now I try to write a console program and get "someU" from the command line.
Therefore I changed the type of "checkSimple" to include a (u: Maybe U) as parameter (maybe because the input from the console can be 'nothing'). However I can't get the code to type check.
module CheckMain where
open import Prelude
-- Install Prelude
---- clone this git repo:
---- https://github.com/fkettelhoit/agda-prelude
-- Configure Prelude
--- press Meta/Alt and the letter X together
--- type "customize-group" (i.e. in the mini buffer)
--- type "agda2"
--- expand the Entry "Agda2 Include Dirs:"
--- add the directory
data S : Set where
nat : (n : ℕ) → S
nil : S
sToℕ : S → Maybe ℕ
sToℕ (nat n) = just n
sToℕ _ = nothing
data U : Set where
nat : U
El : U → Set
El nat = ℕ
sToStat : (u : U) → S → Maybe (El u)
sToStat nat s = sToℕ s
-- Basic Test
test1 : Maybe ℕ
test1 = sToStat nat (nat 1)
{- THIS WORKS -}
checkSimple : (u : U) → Maybe (El u)
checkSimple someU = sToStat someU (nat 1)
{- HERE IS THE ERROR -}
-- in contrast to checkSimple we only get a (Maybe U) as a parameter
-- (e.g. from console input)
check : {u : U} (u1 : Maybe U) → Maybe (El u)
check (just someU) = sToStat someU (nat 1)
check _ = nothing
{- HER IS THE ERROR MESSAGE -}
{-
someU != .u of type U
when checking that the expression sToStat someU (nat 1) has type
Maybe (El .u)
-}
The issue is quite simple in nature: the resulting type of sToStat depends on the value of its first argument (u : U in your code); when you later use sToStat inside check, you want the return type to depend on someU - but check promises that its return type depends on the implicit u : U instead!
Now, let's imagine this does typecheck, I'll show you few issues that would arise.
What if u1 is nothing? Well, in that case we would like to return nothing as well. nothing of what type? Maybe (El u) you might say, but here's the thing - u is marked as an implicit argument, which means the compiler will try to infer it for us from other context. But there's no other context that would pin down the value of u!
Agda will most likely complain about unsolved metavariables whenever you try to use check, which means you have to write the value of u everywhere you use check, thus defeating the point of marking u implicit in the first place. In case you didn't know, Agda gives us a way to provide implicit arguments:
check {u = nat} {- ... -}
but I digress.
Another issue becomes apparent if you extend U with more constructors:
data U : Set where
nat char : U
for example. We'll also have to account for this extra case in few other functions, but for the purpose of this example, let's just have:
El : U → Set
El nat = ℕ
El char = Char
Now, what is check {u = char} (just nat)? sToStat someU (nat 1) is Maybe ℕ, but El u is Char!
And now for the possible solution. We need to make the result type of check depend on u1 somehow. If we had some kind of unJust function, we could write
check : (u1 : Maybe U) → Maybe (El (unJust u1))
You should see the problem with this code right away - nothing guarantees us that u1 is just. Even though we are going to return nothing, we must still provide a correct type!
First off, we need to pick some type for the nothing case. Let's say I would like to extend U later, so I need to pick something neutral. Maybe ⊤ sounds pretty reasonable (just a quick reminder, ⊤ is what () is in Haskell - the unit type).
How can we make check return Maybe ℕ in some cases and Maybe ⊤ in others? Ah, we could use a function!
Maybe-El : Maybe U → Set
Maybe-El nothing = Maybe ⊤
Maybe-El (just u) = Maybe (El u)
That's exactly what we needed! Now check simply becomes:
check : (u : Maybe U) → Maybe-El u
check (just someU) = sToStat someU (nat 1)
check nothing = nothing
Also, this is the perfect opportunity to mention the reduction behaviour of these functions. Maybe-El is very suboptimal in that regard, let's have a look at another implementation and do a bit of comparing.
Maybe-El₂ : Maybe U → Set
Maybe-El₂ = Maybe ∘ helper
where
helper : Maybe U → Set
helper nothing = ⊤
helper (just u) = El u
Or perhaps we could save us some typing and write:
Maybe-El₂ : Maybe U → Set
Maybe-El₂ = Maybe ∘ maybe El ⊤
Alright, the previous Maybe-El and the new Maybe-El₂ are equivalent in the sense that they give same answers for same inputs. That is, ∀ x → Maybe-El x ≡ Maybe-El₂ x. But there's one huge difference. What can we tell about Maybe-El x without looking at what x is? That's right, we can't tell anything. Both function cases need to know something about x before continuing.
But what about Maybe-El₂? Let's try the same: we start with Maybe-El₂ x, but this time, we can apply (the only) function case. Unrolling few definitions, we arrive at:
Maybe-El₂ x ⟶ (Maybe ∘ helper) x ⟶ Maybe (helper x)
And now we are stuck, because to reduce helper x we need to know what x is. But look, we got much, much farther than with Maybe-El. Does it make a difference?
Consider this very silly function:
discard : {A : Set} → Maybe A → Maybe ⊤
discard _ = nothing
Naturally, we would expect the following function to typecheck.
discard₂ : Maybe U → Maybe ⊤
discard₂ = discard ∘ check
check is producing Maybe y for some y, right? Ah, here comes the problem - we know that check x : Maybe-El x, but we don't know anything about x, so we can't assume Maybe-El x reduces to Maybe y either!
On the Maybe-El₂ side, the situation is completly different. We know that Maybe-El₂ x reduces to Maybe y, so the discard₂ now typechecks!

Resources