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

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.

Related

How to prove ((x :: xs) = (y :: ys)) given (x = y) & (xs = ys)

I am learning Idris and I have a bit of a noob question.
I am doing exercise 2 of chapter 8.3 of the book on type driven development with Idris. The point is to implement DecEq for your own Vector. This is how far I got:
data Vect : Nat -> Type -> Type where
Nil : Vect 0 elem
(::) : elem -> Vect n elem -> Vect (S n) elem
headUnequal : {xs : Vect n a} -> {ys : Vect n a} -> (contra : (x = y) -> Void) -> ((x :: xs) = (y :: ys)) -> Void
headUnequal contra Refl = contra Refl
tailsUnequal : {xs : Vect n a} -> {ys : Vect n a} -> (contra : (xs = ys) -> Void) -> ((x :: xs) = (y :: ys)) -> Void
tailsUnequal contra Refl = contra Refl
headAndTailEq : {xs : Vect n a} -> {ys : Vect n a} -> (xEqY : x = y) -> (xsEqYs : xs = ys) -> ((x :: xs) = (y :: ys))
headAndTailEq xEqY xsEqYs = ?hole
implementation DecEq a => DecEq (Vect n a) where
decEq [] [] = Yes Refl
decEq (x :: xs) (y :: ys) =
case decEq x y of
No xNeqY => No $ headUnequal xNeqY
Yes xEqY => case decEq xs ys of
No xsNeqYs => No $ tailsUnequal xsNeqYs
Yes xsEqYs => Yes $ headAndTailEq xEqY xsEqYs
How do I fill ?hole?
I've seen the solution on https://github.com/edwinb/TypeDD-Samples/blob/master/Chapter8/Exercises/ex_8_3.idr. With that knowledge I can make my solution work:
implementation DecEq a => DecEq (Vect n a) where
decEq [] [] = Yes Refl
decEq (x :: xs) (y :: ys) =
case decEq x y of
No xNeqY => No $ headUnequal xNeqY
Yes Refl => case decEq xs ys of
No xsNeqYs => No $ tailsUnequal xsNeqYs
Yes Refl => Yes Refl
But honestly, why does this work? Why does the final Yes Refl only work if I don't name the proofs?
Thank you!
The important difference is the value matching in the case-blocks, not the naming of the proofs. If you inspect the first case with
decEq (x :: xs) (y :: ys) =
case decEq x y of
No xNeqY => No $ headUnequal xNeqY
Yes Refl => ?hole
you will see, that the ?hole only needs Dec (x :: xs = x :: ys). In your version on the other hand, ?hole is Dec (x :: xs = y :: ys):
decEq (x :: xs) (y :: ys) =
case decEq x y of
No xNeqY => No $ headUnequal xNeqY
Yes xEqY => ?hole
Here, xEqY : x = y. Idris has no special understanding of =, so this simply means, that there is a value xEqY that has the type x = y (and there is no further inspection on what xEqY could be). If you match on Refl, Idris can unify x and y, because Refl is a constructor for x = x - the values are the same. Thus you gain more information with pattern matching; instead of an opaque variable name, you get a concrete value. As a rule of thumb: always pattern match until you have enough information on the right hand side.
With this, your proof can also be implemented easily:
headAndTailEq : {xs : Vect n a} -> {ys : Vect n a} -> (xEqY : x = y) -> (xsEqYs : xs = ys) -> ((x :: xs) = (y :: ys))
headAndTailEq Refl Refl = Refl

Idris rewrite does not happen

import Data.Vect
import Data.Vect.Quantifiers
sameKeys : Vect n (lbl, Type) -> Vect n (lbl, Type) -> Type
sameKeys xs ys = All (uncurry (=)) (zip (map fst xs) (map fst ys))
g : {xs,ys : Vect n (lbl, Type)} -> sameKeys xs ys -> map (\b => fst b) xs = map (\b => fst b) ys
g {xs = []} {ys = []} [] = Refl
g {xs = x::xs} {ys = y::ys} (p::ps) = rewrite g ps in ?q
This is the error I see:
*main> :load main.idr
Type checking ./main.idr
main.idr:57:3:When checking right hand side of g with expected type
map (\b => fst b) (x :: xs) = map (\b6 => fst b6) (y :: ys)
rewriting
Data.Vect.Vect n implementation of Prelude.Functor.Functor, method map (\b => fst b) xs
to
Data.Vect.Vect n implementation of Prelude.Functor.Functor, method map (\b6 => fst b6) ys
did not change type
fst x :: Data.Vect.Vect n implementation of Prelude.Functor.Functor, method map (\b => fst b) xs = fst y :: Data.Vect.Vect n implementation of Prelude.Functor.Functor, method map (\b6 => fst b6) ys
Holes: Main.g
Why does it not rewrite it?
This is happening because Idris somehow fails to infer the correct implicit arguments to g, instead it introduces fresh vectors in the context.
As a workaround I can suggest to prove it as follows. First, we'll need a congruence lemma for two-argument functions:
total
cong2 : {f : a -> b -> c} -> (a1 = a2) -> (b1 = b2) -> f a1 b1 = f a2 b2
cong2 Refl Refl = Refl
Now the proof of the original lemma is trivial:
total
g : sameKeys xs ys -> map (\b => fst b) xs = map (\b => fst b) ys
g {xs = []} {ys = []} x = Refl
g {xs = x :: xs} {ys = y :: ys} (p :: ps) = cong2 p $ g ps

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)

In Idris, how to write a "vect generator" function that take a function of index in parameter

I'm trying to write in Idris a function that create a Vect by passing the size of the Vect and a function taking the index in parameter.
So far, I've this :
import Data.Fin
import Data.Vect
generate: (n:Nat) -> (Nat -> a) ->Vect n a
generate n f = generate' 0 n f where
generate': (idx:Nat) -> (n:Nat) -> (Nat -> a) -> Vect n a
generate' idx Z f = []
generate' idx (S k) f = (f idx) :: generate' (idx + 1) k f
But I would like to ensure that the function passed in parameter is only taking index lesser than the size of the Vect.
I tried that :
generate: (n:Nat) -> (Fin n -> a) ->Vect n a
generate n f = generate' 0 n f where
generate': (idx:Fin n) -> (n:Nat) -> (Fin n -> a) -> Vect n a
generate' idx Z f = []
generate' idx (S k) f = (f idx) :: generate' (idx + 1) k f
But it doesn't compile with the error
Can't convert
Fin n
with
Fin (S k)
My question is : is what I want to do possible and how ?
The key idea is that the first element of the vector is f 0, and for the tail, if you have k : Fin n, then FS k : Fin (S n) is a "shift" of the finite number that increments its value and its type at the same time.
Using this observation, we can rewrite generate as
generate : {n : Nat} -> (f : Fin n -> a) -> Vect n a
generate {n = Z} f = []
generate {n = S _} f = f 0 :: generate (f . FS)
Another possibility is to do what #dfeuer suggested and generate a vector of Fins, then map f over it:
fins : (n : Nat) -> Vect n (Fin n)
fins Z = []
fins (S n) = FZ :: map FS (fins n)
generate' : {n : Nat} -> (f : Fin n -> a) -> Vect n a
generate' f = map f $ fins _
Proving generate f = generate' f is left as en exercise to the reader.
Cactus's answer appears to be about the best way to get what you asked for, but if you want something that can be used at runtime, it will be quite inefficient. The essential reason for this is that to weaken a Fin n to a Fin n+m requires that you completely deconstruct it to change the type of its FZ, and then build it back up again. So there can be no sharing at all between the Fin values produced for each vector element. An alternative is to combine a Nat with a proof that it is below a given bound, which leads to the possibility of erasure:
data NFin : Nat -> Type where
MkNFin : (m : Nat) -> .(LT m n) -> NFin n
lteSuccLeft : LTE (S n) m -> LTE n m
lteSuccLeft {n = Z} prf = LTEZero
lteSuccLeft {n = (S k)} {m = Z} prf = absurd (succNotLTEzero prf)
lteSuccLeft {n = (S k)} {m = (S j)} (LTESucc prf) = LTESucc (lteSuccLeft prf)
countDown' : (m : Nat) -> .(m `LTE` n) -> Vect m (NFin n)
countDown' Z mLTEn = []
countDown' (S k) mLTEn = MkNFin k mLTEn :: countDown' k (lteSuccLeft mLTEn)
countDown : (n : Nat) -> Vect n (NFin n)
countDown n = countDown' n lteRefl
countUp : (n : Nat) -> Vect n (NFin n)
countUp n = reverse $ countDown n
generate : (n : Nat) -> (NFin n -> a) -> Vect n a
generate n f = map f (countUp n)
As in the Fin approach, the function you pass to generate does not need to work on all naturals; it only needs to handle ones less than n.
I used the NFin type to explicitly indicate that I want the LT m n proof to be erased in all cases. If I didn't want/need that, I could just use (m ** LT m n) instead.

How can I arrange to pattern match on a dependent view?

I've written some simple types for viewing Vect values:
data SnocVect : Vect n a -> Type where
SnocNil : SnocVect []
Snoc : (xs : Vect n a) -> (x : a) -> SnocVect (xs ++ [x])
data Split : (m : Nat) -> Vect n a -> Type where
MkSplit : (xs : Vect j a) -> (ys : Vect k a) ->
Split j (xs ++ ys)
Now it seems to me entirely reasonable that if I have a Split separating the last element of a vector, I should be able to convert that into a SnocVect:
splitToSnocVect : .{xs : Vect (S n) a} -> Split n xs ->
SnocVect xs
Unfortunately, I can't seem to find any way to implement this thing. In particular, I haven't found any way whatsoever to get it to let me pattern match on the Split n xs argument, without which I obviously can't get anywhere. I think the basic problem is that I have something of type
Split j (ps ++ [p])
and since ++ isn't injective, I need to work some sort of magic to convince the type checker that things make sense. But I don't understand this well enough to say for sure.
I finally got it! I imagine there must be a better way, but this works.
vectLengthConv : {auto a : Type} -> m = n ->
Vect m a = Vect n a
vectLengthConv prf = rewrite prf in Refl
splitToSnocVect' : .(n : Nat) -> .(xs : Vect m a) ->
.(m = n+1) -> Split n xs -> SnocVect xs
splitToSnocVect' n (ys ++ zs) prf (MkSplit {k} ys zs)
with (vectLengthConv (plusLeftCancel n k 1 prf))
splitToSnocVect' n (ys ++ []) prf
(MkSplit {k = Z} ys []) | Refl impossible
splitToSnocVect' n (ys ++ (z :: [])) prf
(MkSplit {k = (S Z)} ys (z :: [])) | lenconv =
Snoc ys z
splitToSnocVect' n (ys ++ zs) prf
(MkSplit {k = (S (S k))} ys zs) | Refl impossible
splitToSnocVect : .{n : Nat} -> .{xs : Vect (S n) a} ->
Split n xs -> SnocVect xs
splitToSnocVect {n} {xs} splt =
splitToSnocVect' n xs (plusCommutative 1 n) splt
Edit
David Christiansen suggests nixing vectLengthConv and instead using cong {f=\len=>Vect len a} (plusLeftCancel n k 1 prf) in the with clause. This helps a little.