When practicing using dependent pairs in Idris, I have encountered an unexpected difference in behavior between compiled programs and the REPL. The following datatype is what I am testing with:
(a : Type ** b : Type ** Arrow a b)
Which should represent some relation between type a and type b. Given an instance of the above, I would like to extract the "proof" term of the type. I can do this from the REPL with DPair.snd $ DPair.snd <some-instance> and everything works fine. However, if I try to make a function:
unwrap : (a ** b ** Arrow a b) -> Arrow a b
unwrap x = DPair.snd $ DPair.snd x
the program will compile, but will fail when I try to call it. The error message returned is
(input): No such variable b
Has anyone encountered this or knows of a solution?
What you want to achieve is not possible. If you look at the type of unwrap : (a1 : Type ** b1 : Type ** Arrow a b) -> Arrow a b you see that it uses a different datatype than (a : Type ** b : Type ** Arrow a b). That's because the arguments a, b are quantified beforehand - setting the resulting type (which is also the difference to the REPL case; there you aren't bound to the arguments). So with :set showimplicit it is
Main.unwrap : {b : Type} -> {a : Type} ->
(a1 : Type ** b1 : Type ** Main.Arrow a b) ->
Main.Arrow a b
That's the thing about dependent pairs, you can't restrict them easily. Take a look at Vect.filter : (elem -> Bool) -> Vect len elem -> (p : Nat ** Vect p elem) - if we had a function like unwrap : (p : Nat ** Vect p elem) -> Vect p elem, we wouldn't need dependent pair in the first place.
Instead, a function that would call unwrap would need to inspect p and then handle the Vect accordingly. Sadly, we can't easily inspect types (at least if you want to generalize for all types). So your best bet is: don't use dependent types here.
I realise I'm a year and a half late, but... This absolutely is possible! You just need to remember that the type a ** P is just syntactic sugar for DPair a (\x => P a); in the latter form, nothing special is going on whatsoever and so you can use your a and b just like you'd expect. We can also gain insight from how DPair.snd is typed in the standard library:
Idris> :t DPair.snd
snd : (x : DPair a P) -> P (fst x)
So, to extract the a-value from our pair, we simply call fst on that pair. How intuitive! (fst itself simply has the type DPair a P -> a). To get the b-value, which is the first value of the second part of our pair, we call fst . snd on the outermost pair. Therefore, your function should look like:
unwrap : (x : DPair a (DPair b . Arrow)) -> Arrow (fst x) (snd $ fst x)
unwrap x = snd (snd x)
(or, equivalently:)
unwrap : (x : DPair a (\theA => DPair b (\theB => Arrow theA theB))) -> ...
For whatever reason, unwrap = DPair.snd . DPair.snd doesn't work... but that's not too much of an issue.
Related
From REPL how does not ensures that the a list is indeed interpret as a vector instead?
For example if I type:
:t Vect
I get Vect : Nat -> Type -> Type which makes absolute sense, if I type
:t Vect 2
I get Vect : Type -> Type which makes again absolute sense. But I try now:
:t Vect 2 [1,2]
and get an error
Can't disambiguate since no name has a suitable type:
Prelude.List.::, Prelude.Stream.::, Data.Vect.::
I was hoping to see instead [1,2] : Vect 2 Int instead. What I am doing wrong? I also have issues when using the function the when trying to interpret a list as vector.
Any suggestion?
the : (a : Type) -> a -> a takes a type and a value of that type and returns that value. So if the target type cannot be inferred from context, like in the REPL, you can use the (Vect 2 Int) [1,2] to specify what you mean with [1,2].
(Vect 2 [1,2] tries to use the List, Stream or Vect [1,2] as the argument in Vect 2 : Type -> Type. But unlike e.g. Int, the list [1,2] is not a Type, so that throws you that error.)
I am experimenting with Idris a lot lately and came up with the following "type level definition of a set":
mutual
data Set : Type -> Type where
Empty : Set a
Insert : (x : a) -> (xs : Set a) -> Not (Elem x xs) -> Set a
data Elem : (x : a) -> Set a -> Type where
Here : Elem x (Insert x xs p)
There : Elem x xs -> Elem x (Insert y xs p)
So a set is either empty or it consists of a set and an additional element that is proven not to be in that set already.
When I totality check this, I get the error
[...] is not strictly positive
for Insert, Here and There. I have been searching the documentation for terms like "strictly positive" and the totality checker in general, but I cannot figure out why this case in particular is not total (or strictly positive). Can somebody explain this?
The natural next question then is of course how to "fix" it. Can I somehow change the definition, keeping its semantics, so that it totality checks?
Since I don't really need the definition to look like this (it is only an experiment after all) it would also be interesting to know whether there is another, somehow more idiomatic way to represent Sets at the type level that is total.
This SO post explains what strictly positive types are and why they matter. In your case, since Not (Elem x xs) simply means a function Elem x xs -> Void, this is where the "type being defined occurring on the left-hand side of an arrow" comes from.
Can you make do with something like this?
mutual
data Set : Type -> Type where
Empty : Set a
Insert : (x : a) -> (xs : Set a) -> NotElem x xs -> Set a
data NotElem : (x : a) -> Set a -> Type where
NotInEmpty : NotElem x Empty
NotInInsert : Not (x = y) -> NotElem x ys -> NotElem x (Insert y ys p)
I want to prove or falsify forall (P Q : Prop), (P -> Q) -> (Q -> P) -> P = Q. in Coq. Here is my approach.
Inductive True2 : Prop :=
| One : True2
| Two : True2.
Lemma True_has_one : forall (t0 t1 : True), t0 = t1.
Proof.
intros.
destruct t0. destruct t1.
reflexivity.
Qed.
Lemma not_True2_has_one : (forall (t0 t1 : True2), t0 = t1) -> False.
Proof.
intros.
specialize (H One Two).
inversion H.
But, inversion H does nothing. I think maybe it's because the coq's proof independence (I'm not a native English speaker, and I don't know the exact words, please forgive my ignorance), and coq makes it impossible to prove One = Two -> False. But if so why has to coq eliminate the content of a proof?
Without the above proposition, I can't prove the followings or their negations.
Lemma True_neq_True2 : True = True2 -> False.
Theorem iff_eq : forall (P Q : Prop), (P -> Q) -> (Q -> P) -> P = Q.
So my question is:
How to or is that possible to prove or falsify forall (P Q : Prop),
(P -> Q) -> (Q -> P) -> P = Q. in Coq?
Why inversion H does nothing; does it's because the coq's proof independence, and if so, why does Coq waste energy in doing this.
The principle you're mentioning, forall P Q : Prop, (P <-> Q) -> P = Q, is usually known as propositional extensionality. This principle is not provable in Coq's logic, and originally the logic had been designed so that it could be added as an axiom with no harm. Thus, in the standard library (Coq.Logic.ClassicalFacts), one can find many theorems about this principle, relating it to other well-known logical principles of classical reasoning. Surprisingly, it was recently found out that Coq's logic is incompatible with this principle, but for a very subtle reason. This is considered a bug, since the logic had been designed so that this could be added as an axiom with no harm. They wanted to fix this problem in the new version of Coq, but I don't know what the current status of that is. As of version 8.4, propositional extensionality is inconsistent in Coq.
In any case, if this bug is fixed in future versions of Coq, it should not be possible to prove nor disprove this principle in Coq. In other words, the Coq team wants this principle to be independent of Coq's logic.
inversion H doesn't do anything there because the rules for reasoning about proofs (things whose type is a Prop) are different from the ones for reasoning about non-proofs (things whose type is a Type). You may know that proofs in Coq are just terms. Under the hood, inversion is essentially constructing the following term:
Definition true_not_false : true <> false :=
fun H =>
match H in _ = b
return if b then True else False
with
| eq_refl => I
end.
If you try to do the same with a version of bool in Prop, you get a more informative error:
Inductive Pbool : Prop :=
| Ptrue : Pbool
| Pfalse : Pbool.
Fail Definition Ptrue_not_Pfalse : Ptrue <> Pfalse :=
fun H =>
match H in _ = b
return if b then True else False
with
| eq_refl => I
end.
(* The command has indeed failed with message: *)
(* => Error: *)
(* Incorrect elimination of "b" in the inductive type "Pbool": *)
(* the return type has sort "Type" while it should be "Prop". *)
(* Elimination of an inductive object of sort Prop *)
(* is not allowed on a predicate in sort Type *)
(* because proofs can be eliminated only to build proofs. *)
Indeed, one of the reasons for this is that Coq was designed to be compatible with another principle called proof irrelevance (I think that's what you meant by "proof independence").
How can we use an implicit variable inside a function? Reducing to the simplest possible case, is it possible to have:
dim : Vect n a -> Nat
dim vec = n
without getting the error:
When elaborating right hand side of rep:
No such variable n
Is there a way to access there values from inside? Or is it the same as asking for n inside sin n?
In this case, is it possible to prove that Vect is a "bijection" and recover the variables from there?
There is really no such variable n because it is not bounded by pattern matching.
You need to explicitly bring implicit variables in scope:
dim : Vect n a -> Nat
dim {n} vec = n
It is possible to view them in idris REPL:
*> :set showimplicits
*> :t dim
Main.dim : {n : Prelude.Nat.Nat} -> {a : Type} ->
(__pi_arg : Prelude.Vect.Vect n a) -> Prelude.Nat.Nat
Is it possible to define a simple syntactic notion of equality (similar to what GHC might automatically derive as the Eq instance for a Haskell 98 type), without either explicitly proving that each data constructor is injective, or doing something analogous, such as defining the retraction of each constructor and using cong?
In other words, is it possible to exploit the injectivity of data constructors more directly, rather than having to introduce one auxiliary function per constructor?
The following uses the natural numbers as an example.
module Eq where
open import Function
open import Relation.Binary
open import Relation.Binary.PropositionalEquality
open import Relation.Nullary
data ℕ : Set where
zero : ℕ
suc : ℕ → ℕ
-- How to eliminate these injectivity proofs?
suc-injective : ∀ {n m} → suc n ≡ suc m → n ≡ m
suc-injective refl = refl
_≟_ : Decidable {A = ℕ} _≡_
zero ≟ suc _ = no (λ ())
suc _ ≟ zero = no (λ ())
zero ≟ zero = yes refl
suc n ≟ suc m with n ≟ m
suc n ≟ suc .n | yes refl = yes refl
... | no n≢m = no (n≢m ∘ suc-injective)
One could replace suc-injective by cong (λ { zero → zero ; (suc x) → x }), i.e. by defining a function which inverts suc, but that still requires boilerplate of one auxiliary function per constructor, and such functions are somewhat ugly to define because of the need to be total.
(Usual caveats re. missing something obvious apply.)
Ulf Norell's prelude for Agda contains a mechanism for automatically deriving decidable equality for a given datatype. The code is based on Agda's reflection mechanism and automatically generated extended lambdas for proving injectivity of constructors. I recommend taking a look at the code, even though it's not always as simple as it could be.