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

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.

Related

Applying known proofs in Idris 1 interactive elaborator

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

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 to prove that the boolean inequality of a type with itself is uninhabited in Idris?

I was wondering how to prove that (So (not (y == y))) is an instance of Uninhabited, and I'm not sure how to go about it. Is it provable in Idris, or is not provable due to the possibility of a weird Eq implementation for y?
The Eq interface does not require an implementation to follow the normal laws of equality. But, we can define an extended LawfulEq interface which does:
%default total
is_reflexive : (t -> t -> Bool) -> Type
is_reflexive {t} rel = (x : t) -> rel x x = True
is_symmetric : (t -> t -> Bool) -> Type
is_symmetric {t} rel = (x : t) -> (y : t) -> rel x y = rel y x
is_transitive : (t -> t -> Bool) -> Type
is_transitive {t} rel = (x : t) -> (y : t) -> (z : t) -> rel x y = True -> rel x z = rel y z
interface Eq t => LawfulEq t where
eq_is_reflexive : is_reflexive {t} (==)
eq_is_symmetric : is_symmetric {t} (==)
eq_is_transitive : is_transitive {t} (==)
The result asked for in the question can be proved for type Bool:
so_false_is_void : So False -> Void
so_false_is_void Oh impossible
so_not_y_eq_y_is_void : (y : Bool) -> So (not (y == y)) -> Void
so_not_y_eq_y_is_void False = so_false_is_void
so_not_y_eq_y_is_void True = so_false_is_void
The result can be proved not true for the following Weird type:
data Weird = W
Eq Weird where
W == W = False
weird_so_not_y_eq_y : (y : Weird) -> So (not (y == y))
weird_so_not_y_eq_y W = Oh
The Weird (==) can be shown to be not reflexive, so an implementation of LawfulEq Weird is not possible:
weird_eq_not_reflexive : is_reflexive {t=Weird} (==) -> Void
weird_eq_not_reflexive is_reflexive_eq =
let w_eq_w_is_true = is_reflexive_eq W in
trueNotFalse $ trans (sym w_eq_w_is_true) (the (W == W = False) Refl)
Shersh is right: you can't. Implementations of (==) aren't guaranteed to be reflexive, so it might not be true.
You could restrict the type of y so that you are proving a property of a specific implementation of (==), but I suspect you want to use decEq and (=) instead of So and (==). It's easy to show Not (y = y) is uninhabited.

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.