Applying known proofs in Idris 1 interactive elaborator - idris

I am trying to get some familiarity with theorem proving in Idris1 by exercise and am running into trouble.
Suppose I have the following definition for naturals and the following theorems that I want to prove:
data Natural = Z | S Natural
plus : Natural -> Natural -> Natural
plus x Z = x
plus x (S y) = S (plus x y)
succBoth : {a : Natural} -> {b : Natural} -> (a = b) -> (S a = S b)
succBoth = ?succBothProof
plusZero : (y : Natural) -> plus Z y = y
plusZero = ?plusZeroProof
plusSwitch : (x : Natural) -> (y : Natural) -> plus (S x) y = S (plus x y)
plusSwitch = ?plusSwitchProof
plusComm : (x : Natural) -> (y : Natural) -> plus x y = plus y x
plusComm = ?plusCommProof
I already have written proofs for the first three. Now, when I want to prove the last theorem, I run into necessity of applying an earlier proof.
Idris> :l Peano.idr
Holes: Peano.plusCommProof
*Peano> :elab plusCommProof
-Peano.plusCommProof> intro `{{x}}
...
-Peano.plusCommProof> intro `{{y}}
...
-Peano.plusCommProof> induction (Var `{{y}})
...
-Peano.plusCommProof> compute
...
-Peano.plusCommProof> attack
---------- Other goals: ----------
{Z_103},{S_104}
---------- Assumptions: ----------
x : Natural
y : Natural
---------- Goal: ----------
{hole_7} : x = plus Z x
It would be natural to apply plusZero at this stage, but I run into issues trying to do that. I try to apply it via rewriteWith, keeping in mind that plusZero takes a Natural type argument. I try to supply it with the x variable, thinking that it will be able to infer its Natural type from assumptions, but no luck:
-Peano.plusCommProof> rewriteWith `(plusZero (Var `{{x}}))
(input):1:15-35:When checking argument y to function Peano.plusZero:
Type mismatch between
Raw (Type of Var _)
and
Natural (Expected type)
How does one "cast" the Raw variable into its type in context?

I couldn't get the Idris 1 version to work but I did install Idris 2 and wrote the proofs in its style instead.
module Peano
data Natural = Zero | Succ Natural
plus : Natural -> Natural -> Natural
plus x Zero = x
plus x (Succ y) = Succ (plus x y)
succBoth : {a : Natural} -> {b : Natural} -> (a = b) -> (Succ a = Succ b)
succBoth rfl = cong (\ a => Succ a) rfl
plusZero : (y : Natural) -> plus Zero y = y
plusZero Zero = Refl
plusZero (Succ y)
= let assumption = plusZero y in
rewrite assumption in Refl
plusSwitch : (x : Natural) -> (y : Natural) ->
plus (Succ x) y = Succ (plus x y)
plusSwitch x Zero = Refl
plusSwitch x (Succ y)
= let assumption = plusSwitch x y in
rewrite assumption in Refl
plusComm : (x : Natural) -> (y : Natural) -> plus x y = plus y x
plusComm x Zero = rewrite plusZero x in Refl
plusComm x (Succ y)
= let assumption = plusComm x y in
rewrite plusSwitch y x in
rewrite assumption in Refl
Admittedly much more compact but I prefer the Idris 1 :elab style for readability

Related

Compiler introducing extra interface requirements when using functions returning dependent pairs

This is rather complicated. Sorry I could'n make the example simpler. I'm trying to formalize a theory and interfaces A and B represent my axioms. X and Y are some objects in the theory, mkY creates a Y from two Xs and PropA, PropY and PropYY are some statements about these objects:
interface A a where
PropA : a -> Type
interface B where
X : Type
Y : Type
PropY : Y -> Type
mkY : A X => (x, y : X) -> (z : Y ** PropY z)
PropYY : Y -> Type
mkPropY : A X => {x : X} -> {y : Y} -> PropA x -> PropY y -> PropYY y
lemma1 : (B, A X) => (x, y : X) -> PropA x -> (z : Y ** PropYY z)
lemma1 x y prop_a =
let (z ** propZ) = mkY x y in
(z ** mkPropY prop_a propZ)
Unfortunately rather obvious lemma1 does not compile:
When checking right hand side of Example.case block in lemma1 at /home/sven/code/idris/geometry/src/Euclid/Example.idr:17:9-20 with expected type
(z1 : Y ** PropYY z1)
When checking an application of function Example.mkPropY:
Type mismatch between
PropA x1 (Type of prop_a)
and
PropA x (Expected type)
It seems to me Idris refuses to unify requirement A X from the function header with that introduced by mkY function. When I replace mkPropY prop_a propZ with a hole and ask for its type, I get this:
constraint : B
z : Y
propZ : PropY z
x : X
y : X
constraint1 : A X
prop_a : PropA x
constraint2 : A X
--------------------------------------
whatIsIt : PropYY z
Here constraint1 and constraint2 are the same, and yet there's two of them, which seems to be the root cause of the problem. So why does Idris introduce this additional constraint and how do I make it work?
I'm not sure why Idris thinks with mkY there could be another constraint in play (as by the looks of it nothing in the hole is constrained by it, even with :set showimplicits). Maybe someone else can explain why, but for now it usually helps to make constraints explicit:
lemma1 : (B, a_const : A X) => (x, y : X) -> PropA x -> (z : Y ** PropYY z)
lemma1 #{a_const} x y prop_a =
let (z ** propZ) = mkY #{a_const} x y in
(z ** mkPropY prop_a propZ)
(Maybe rewriting B as interface B x y where; … would help, so the scope over X and Y is clearer, but I didn't try this.)

How can I reference an Idris interface method from within the same interface declaration?

I built a little TotalOrder class that has stronger proof properties than the regular Ord class. The problem is that these properties need to refer to each other in ways I'm not sure how to do, syntactically.
I need to reference my lessThan type in the other methods in the interface, but it seems to be getting treated as a regular (implicitly forall'd) variable.
module Order
%default total
public export
data Ordering : (t -> t -> Type) -> t -> t -> Type where
LessThan : f x y -> Ordering f x y
Equal : x = y -> Ordering f x y
GreaterThan : f y x -> Ordering f x y
public export
interface TotalOrder a where
lessThan : a -> a -> Type
compare : (x, y : a) -> Ordering lessThan x y
ltNeq : lessThan x y -> x = y -> Void
ltNgt : lessThan x y -> lessThan y x -> Void
-- Implementation for Nats
compareNat : (x, y : Nat) -> Ordering LT x y
compareNat x y = ...
ltNeqNat : LT x y -> x = y -> Void
ltNeqNat lt eq = ...
ltNgtNat : LT x y -> LT y x -> Void
ltNgtNat lt gt = ...
implementation TotalOrder Nat where
lessThan = LT
compare = compareNat -- THIS LINE REFUSES TO COMPILE
ltNeq = ltNeqNat
ltNgt = ltNgtNat
As best I can determine, the typechecker automatically assumes that the lessThans in function position in ltNeq and ltNgt are the same as the lessThan declared in the interface, but the lessThan in argument position in compare is treated as a regular argument to compare, meaning that the type for the Nat implementation is
compare : {lessThan : Nat -> Nat -> Type} -> (x, y : Nat) -> Ordering lessThan x y
rather than
compare : (x, y : Nat) -> Ordering LT x y
and compare = compareNat no longer typechecks. When I run into this problem in top-level functions, fully-qualifying the name works, but I'm not sure what the fully-qualified name here would be, and the obvious ideas (Order.lessThan, TotalOrder.lessThan, Order.TotalOrder.lessThan) all get "no such variable"d.

How can I use a proof I've made in Idris to inform the compiler that my type signature is correct?

I have a function count in idris, defined as :
count : Eq a => a -> Vect n a -> Nat
count x [] = Z
count x (y::ys) = with (x == y)
| True = S (count x ys)
| False = count x ys
And a proof of the maximum value count can return:
countLTELen : Eq a => (x : a) -> (l : Vect n a) -> LTE (count x l) n
countLTELen x [] = lteRefl
countLteLen x (y::ys) with (x == y)
| True = LTESucc (countLTELen x ys)
| False = lteSuccRight (countLTELen x ys)
which is all well and good. I now want to write a function which removes all of an element from a list, removeAll :
removeAll : Eq a => (x : a) -> (l : Vect n a) -> Vect (n - (count x l)) a
removeAll x [] = []
removeAll x (y::ys) with (x == y)
| True = removeAll x ys
| False = x :: removeAll x ys
But this definition gives an error:
|
56 | removeAll : Eq a => (x : a) -> (l : Vect n a) -> Vect (n - (count x l)) a
| ^
When checking type of Proof.removeAll:
When checking argument smaller to function Prelude.Nat.-:
Can't find a value of type
LTE (count a n constraint x l) n
How can I use my proof to inform Idris that this type signature is correct?
Right now, Idris can't find the proof {auto smaller : LTE n m} for (-).
So either you need to be explicit:
removeAll : Eq a => (x : a) -> (l : Vect n a) ->
Vect ((-) {smaller=countLTELen x l} n (count x l) ) a
Or, because smaller is an auto-argument, you can hint the compiler to your proof function. Then this function will be tried when auto-finding a value for LTE (count x l) n.
%hint
countLTELen : Eq a => (x : a) -> (l : Vect n a) -> LTE (count x l) n

Why does Idris' Refl sometimes not type-check?

I'm working through the Idris book, and I'm doing the first exercises on proof.
With the exercise to prove same_lists, I'm able to implement it like this, as matching Refl forces x and y to unify:
total same_lists : {xs : List a} -> {ys : List a} ->
x = y -> xs = ys -> x :: xs = y :: ys
same_lists Refl Refl = Refl
However, when I try to prove something else in the same manner, I get mismatches. For example:
total allSame2 : (x, y : Nat) -> x = y -> S x = S y
allSame2 x y Refl = Refl
The compiler says:
Type mismatch between
y = y (Type of Refl)
and
x = y (Expected type)
If I case-match after the =, either explicitly or with a lambda, it works as expected:
total allSame2 : (x : Nat) -> (y : Nat) -> x = y -> S x = S y
allSame2 x y = \Refl => Refl
What's the difference here?
Another modification that works is making the problematic arguments implicit:
total allSame2 : {x : Nat} -> {y : Nat} -> x = y -> S x = S y
allSame2 Refl = Refl
I do not know all the details, but I can give you a rough idea. In Idris, the parameter lists of named functions are special in that it is part of dependent pattern matching. When you pattern match it also rewrites the other parameters.
same_lists x y Refl = Refl is not valid, I roughly guess, because Idris is rewriting x and y to be the same, and you are not allowed to then give different names to this single value — I hope someone can give a better explanation of this mechanism. Instead you may use same_lists x x Refl = Refl — and note that the name x is not important, just that the same name is used in both sites.
A lambda parameter is apart from the named parameter list. Therefore, since you are doing the matching in the lambda, Idris is only going to rewrite the other parameters at that point. The key is that with the first example Idris wants to do it all at once because it is part of the same parameter list.
With the final example the only change is that you did not give distinct names to the parameters. It would have also been valid to use all_same _ _ Refl = Refl. When the parameters are implicit, Idris will fill them in correctly for you.
Finally you can consider same_lists = \x, y, Refl => Refl which also works. This is because Idris does not rewrite in unnamed parameter lists (i.e. lambda parameters).

Problems with equational proofs and interface resolution in Idris

I'm trying to model Agda style equational reasoning proofs for Setoids (types with an equivalence relation). My setup is as follows:
infix 1 :=:
interface Equality a where
(:=:) : a -> a -> Type
interface Equality a => VerifiedEquality a where
eqRefl : {x : a} -> x :=: x
eqSym : {x, y : a} -> x :=: y -> y :=: x
eqTran : {x, y, z : a} -> x :=: y -> y :=: z -> x :=: z
Using such interfaces I could model some equational reasoning combinators like
Syntax.PreorderReasoning from Idris library.
syntax [expr] "QED" = qed expr
syntax [from] "={" [prf] "}=" [to] = step from prf to
namespace EqReasoning
using (a : Type, x : a, y : a, z : a)
qed : VerifiedEquality a => (x : a) -> x :=: x
qed x = eqRefl {x = x}
step : VerifiedEquality a => (x : a) -> x :=: y -> (y :=: z) -> x :=: z
step x prf prf1 = eqTran {x = x} prf prf1
The main difference from Idris library is just the replacement of propositional equality and their related functions to use the ones from VerifiedEquality interface.
So far, so good. But when I try to use such combinators, I run in problems that, I believe, are related to interface resolution. Since the code is part of a matrix library that I'm working on, I posted the relevant part of it in the following gist.
The error occurs in the following proof
zeroMatAddRight : ( VerifiedSemiring s
, VerifiedEquality s ) =>
{r, c : Shape} ->
(m : M s r c) ->
(m :+: (zeroMat r c)) :=: m
zeroMatAddRight {r = r}{c = c} m
= m :+: (zeroMat r c)
={ addMatComm {r = r}{c = c} m (zeroMat r c) }=
(zeroMat r c) :+: m
={ zeroMatAddLeft {r = r}{c = c} m }=
m
QED
that returns the following error message:
When checking right hand side of zeroMatAddRight with expected type
m :+: (zeroMat r c) :=: m
Can't find implementation for Semiring a
Possible cause:
./Data/Matrix/Operations/Addition.idr:112:11-118:1:When checking an application of function Algebra.Equality.EqReasoning.step:
Type mismatch between
m :=: m (Type of qed m)
and
y :=: z (Expected type)
At least to me, it appears that this error is related with interface resolution that isn't interacting well with syntax extensions.
My experience is that such strange errors can be solved by passing implicit parameters explicitly. The problem is that such solution will kill the "readability" of equational reasoning combinator proofs.
Is there a way to solve this? The relevant part for reproducing this error is available in previously linked gist.