In Idris, how to show that a non-trivial equality is Refl? - equality

I'm building a little dependently-typed lambda calculus interpreter:
import Data.Vect
%default total
{- fin helper functions and lemmas -}
incrFin : Fin n -> Fin (S n) -> Fin (S n)
incrFin x FZ = FS x
incrFin FZ (FS y) = FZ
incrFin (FS x) (FS y) = FS (incrFin x y)
subrFin : (x : Fin (S n)) -> (y : Fin (S n)) -> (x = y -> Void) -> Fin n
subrFin FZ FZ neq = absurd (neq Refl)
subrFin FZ (FS x) neq = x
subrFin {n = S n} (FS x) FZ neq = FZ
subrFin {n = S n} (FS x) (FS y) neq = FS (subrFin x y (\Refl => neq Refl))
indexOfIncrFin : (x : Fin (S n)) -> (y : Fin n) -> (env : Vect n a) -> (t : a) ->
index (incrFin y x) (insertAt x t env) = index y env
{- elided -}
indexOfSubrFin : {n : Nat} -> {env : Vect n a} -> (neq : (x = y) -> Void) ->
index (subrFin x y neq) env = index y (insertAt x t2 env)
{- elided -}
indexInsertAt : (x : Fin (S n)) -> (t : a) -> (env : Vect n a) -> index x (insertAt x t env) = t
{- elided -}
incrFinChanges : (x : Fin n) -> (y : Fin (S n)) -> Not (incrFin x y = y)
{- elided -}
{- main code -}
data Ty = Base | Arrow Ty Ty
data Expr : Vect n Ty -> Ty -> Type where
Var : (x : Fin n) -> index x env = t -> Expr env t
Con : Expr env Base
App : Expr env (Arrow t1 t2) -> Expr env t1 -> Expr env t2
Abs : (t1 : Ty) -> Expr (t1 :: env) t2 -> Expr env (Arrow t1 t2)
incr : (x : Fin (S n)) -> (tt : Ty) -> Expr env t -> Expr (insertAt x tt env) t
incr x tt (Var y Refl) {env = env} = Var (incrFin y x) (indexOfIncrFin x y env tt)
incr x tt Con = Con
incr x tt (App e1 e2) = App (incr x tt e1) (incr x tt e2)
incr x tt (Abs t1 e) = Abs t1 (incr (FS x) tt e)
subst : (x : Fin (S n)) -> Expr env t' -> Expr (insertAt x t' env) t -> Expr env t
subst {env = env} {t' = t'} x e' (Var y pf) with (decEq x y)
subst {env = env} {t' = t'} x e' (Var x Refl) | Yes Refl = rewrite indexInsertAt x t' env in e'
subst {env = env} {t' = t'} x e' (Var y Refl) | No neq = Var (subrFin x y neq) (indexOfSubrFin neq)
subst x e' Con = Con
subst x e' (App e1 e2) = App (subst x e' e1) (subst x e' e2)
subst x e' (Abs t1 e) = Abs t1 (subst (FS x) (incr FZ t1 e') e)
substIncr : (x : Fin (S n)) -> (e' : Expr env t') -> (e : Expr env t) -> subst x e' (incr x t' e) = e
substIncr x e' (Var y Refl) with (decEq x (incrFin y x))
substIncr x e' (Var y Refl) | Yes eq = absurd (incrFinChanges y x (sym eq))
substIncr x e' (Var y Refl) | No neq = ?substIncr_missingCase
substIncr x e' Con = Refl
substIncr x e' (App e1 e2) = rewrite substIncr x e' e1 in rewrite substIncr x e' e2 in Refl
substIncr x e' (Abs t1 e) = rewrite substIncr (FS x) (incr FZ t1 e') e in Refl
The problem is the last missing case of the substIncr proof. The type won't reduce, because subst only reduces when the proof in Var is identically Refl, and instead it's indexOfIncrFin x y env t'. Now, indexOfIncrFin is total, it always returns Refl, but its type isn't just f x y = z; it, instead, has a complicated term on either side of the equality (index (incrFin y x) (insertAt x t env) = index y env). So when I try to match on it, via with or case, it complains about "type mismatch between index y env = index y env (type of Refl) and index (incrFin y x) (insertAt x t' env) = index y env (expected type)."
The only other thing I could think of was to change the definition of subst to rewrite instead of matching on Refl, but that (a) is kinda uglier, and (b) bogs me down in some kind of rewrite__impl type I understand even less, and which also won't reduce.
Any ideas on how to work around this?

Related

Prove a property of a function with a decEq in it

It's easy to prove
f : Nat -> Nat
proveMe : (x : Nat) -> Maybe Nat
proveMe x = if (f x) == 0 then Just 42 else Nothing
theProof : (x : Nat) -> (f x = Z) -> (Just 42 = proveMe x)
theProof x prf = rewrite prf in Refl
But what if the calculation of Just 42 requires the proof that f x = 0?
proveMe2 : (x : Nat) -> Maybe Nat
proveMe2 x with (decEq (f x) Z)
| Yes prf = Just 42
| No _ = Nothing
theProof2 : (x : Nat) -> (f x = Z) -> (Just 42 = proveMe2 x)
theProof2 x prf = ?howToFillThis
How can I prove it now?
I tried to "follow the structure of the with clause", but when doing so I would have to convince idris that the contra-case is impossible:
theProof3 : (x : Nat) -> (f x = Z) -> (Just 42 = proveMe2 x)
theProof3 x prf with (decEq (f x) Z)
| Yes prf2 = Refl
| No contra impossible -- "...is a valid case"
I had completely forgotten about void : Void -> a. Using Ex falso quodlibet the proof is simply
theProof3 : (x : Nat) -> (f x = Z) -> (Just 42 = proveMe2 x)
theProof3 x prf with (decEq (f x) Z)
| Yes prf2 = Refl
| No contra = void $ contra prf

Hole with Delay in type. How to prove?

I was trying to prove that replicate1 works correctly by showing that all elements of replicate1 n x are x:
all1 : (p : a -> Bool) -> List a -> Bool
all1 p [] = True
all1 p (x :: xs) = p x && all1 p xs
replicate1 : (n: Nat) -> a -> List a
replicate1 Z x = [x]
replicate1 (S k) x = x :: replicate1 k x
all_replicate_is_x : Eq a => {x: a} -> all1 (== x) (replicate1 n x) = True
all_replicate_is_x {n = Z} = ?hole
all_replicate_is_x {n = (S k)} = ?all_replicate_is_x_rhs_2
The base case hole is
Test.hole [P]
`-- a : Type
constraint : Eq a
x : a
-----------------------------------------
Test.hole : x == x && Delay True = True
How to prove this?

How to rewrite: Vect (S (S (n + m))) a -> Vect (S (plus n (S m))) a

I am stuck with Idris (again, sigh). I am doing an exercise on merge sort from the type driven development with Idris book on chapter 10. I have this:
import Data.Vect
import Data.Vect.Views
sort2 : Ord a => (l: a) -> (r: a) -> (a, a)
sort2 l r = if l <= r then (l, r) else (r, l)
needHelp : Vect (S (S (n + m))) a -> Vect (S (plus n (S m))) a
needHelp {n=(S n)} {m=(S m)} (x :: xs) = ?help
vectMerge : Ord a => Vect n a -> Vect m a -> Vect (n + m) a
vectMerge [] ys = ys
vectMerge {n} xs [] = rewrite plusZeroRightNeutral n in xs
vectMerge {n=(S n)} {m=(S m)} (x :: xs) (y :: ys) =
let (f, s) = sort2 x y in
needHelp (f :: s :: (vectMerge xs ys))
I have isolated the needHelp function so you can see the rewrite that I want to achieve. I tried this:
vectMerge : Ord a => Vect n a -> Vect m a -> Vect (n + m) a
vectMerge [] ys = ys
vectMerge {n} xs [] = rewrite plusZeroRightNeutral n in xs
vectMerge {n=(S n)} {m=(S m)} (x :: xs) (y :: ys) =
let (f, s) = sort2 x y in
let tail = (rewrite plusSuccRightSucc n m in s :: vectMerge xs ys) in
f :: tail
But Idris complains:
When checking right hand side of Main.case block in vectMerge with expected type
Vect (S (plus n (S m))) a
rewriting S (plus n m) to plus n (S m) did not change type letty
I don't understand why this doesn't work. Help much appreciated.
rewrite works with respect to your current goal, not wrt to the term you are trying to use to solve the goal (I tried to illustrate it in this answer).
So, here is a possible solution:
import Data.Vect
sort2 : Ord a => (l: a) -> (r: a) -> (a, a)
sort2 l r = if l <= r then (l, r) else (r, l)
vectMerge : Ord a => Vect n a -> Vect m a -> Vect (n + m) a
vectMerge [] ys = ys
vectMerge {n} xs [] = rewrite plusZeroRightNeutral n in xs
vectMerge {n=(S n)} {m=(S m)} (x :: xs) (y :: ys) =
let (f, s) = sort2 x y in
rewrite sym $ plusSuccRightSucc n m in
(f :: s :: (vectMerge xs ys))
sym in sym $ plusSuccRightSucc n m reverses the direction of rewrite.

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

Understanding `decEq`

Given:
*section3> :module Data.Vect
*section3> :let e = the (Vect 0 Int) []
*section3> :let xs = the (Vect _ _) [1,2]
*section3> decEq xs e
(input):1:7:When checking argument x2 to function Decidable.Equality.decEq:
Type mismatch between
Vect 0 Int (Type of e)
and
Vect 2 Integer (Expected type)
Specifically:
Type mismatch between
0
and
2
Why must the Nat arguments equal each other for DecEq?
Note - posted in https://groups.google.com/forum/#!topic/idris-lang/qgtImCLka3I originally
decEq is for homogenous propositional equality:
||| Decision procedures for propositional equality
interface DecEq t where
||| Decide whether two elements of `t` are propositionally equal
total decEq : (x1 : t) -> (x2 : t) -> Dec (x1 = x2)
As you can see, x1 and x2 are both of type t. In your case, you have x1 : Vect 2 Integer and x2 : Vect 0 Int. These are two different types.
You can write your own heterogenous equality decider for Vectors of the same element type by first checking their lengths, then delegating to the homogenous version:
import Data.Vect
vectLength : {xs : Vect n a} -> {ys : Vect m a} -> xs = ys -> n = m
vectLength {n = n} {m = n} Refl = Refl
decEqVect : (DecEq a) => (xs : Vect n a) -> (ys : Vect m a) -> Dec (xs = ys)
decEqVect {n = n} {m = m} xs ys with (decEq n m)
decEqVect xs ys | Yes Refl = decEq xs ys
decEqVect xs ys | No notEq = No (notEq . vectLength)