Why doesn't cong typecheck in Idris 2 - idris

I'm writing a function to test propositional equality of Nat, and it typechecks in Idris 1.
sameNat : (n : Nat) -> (m : Nat) -> Maybe (n = m)
sameNat Z Z = Just Refl
sameNat (S n) (S m) = case sameNat n m of
Just e => Just (cong e)
Nothing => Nothing
sameNat _ _ = Nothing
But it doesn't typecheck in Idris 2 (0.4.0) and I got this error.
Error: While processing right hand side of sameNat. When
unifying n = m and Nat m e -> :: ?x ?xs n m e.
Mismatch between: n = m and Nat m e -> :: ?x ?xs n m e.
It typechecks when I write a specific version of cong and use it.
cong' : n = m -> S n = S m
cong' Refl = Refl
Why doesn't this typecheck and how can I make it typecheck?

The type signature of cong changed:
Idris 1:
cong : (a = b) -> f a = f b
Idris 2:
Prelude.cong : (0 f : (t -> u)) -> a = b -> f a = f b

Related

Is this a bug in Idris's type-checker (or unification)?

The following snippet compiles fine in Idris 2,
divMod2 : Nat -> (Nat, Bool)
divMod2 Z = (Z, False)
divMod2 (S Z) = (Z, True)
divMod2 (S (S n)) = case divMod2 n of (k, r) => (S k, r)
lm : {q:_} -> divMod2 (q+q) = (q, False)
lm {q=0} = Refl
lm {q=S q} = rewrite sym $ plusSuccRightSucc q q in
rewrite lm {q} in Refl
but it caused Idris 1.3.4 to fail:
|
14 | rewrite lm {q} in Refl
| ~~~~~~
When checking right hand side of lm with expected type
divMod2 (S q + S q) = (S q, False)
When checking an application of function rewrite__impl:
Type mismatch between
(q1, False) = (q1, False) (Type of Refl)
and
case divMod2 (plus q q) of (k, r) => (S k, r) = (q1, False) (Expected type)
Specifically:
Type mismatch between
(q1, False)
and
case divMod2 (plus q q) of
(k, r) => (S k, r)
I know Idris 1 has become obsolete, but am still curious about the underlying reason behind this observation. Could someone help to explain this?
I've done a bit more dig here and found surprisingly that Idris1 failed to compile the following even simpler code snippet, which compiles correctly by Idris2:
f : Nat -> (Nat, Bool)
f Z = (Z, False)
f (S n) = case f n of (k, r) => (S k, r)
h2 : {q:_} -> f (S (q+1)) = case f (q+1) of (k, r) => (S k, r)
h2 = Refl
It spit error message:
|
19 | h2 = Refl
| ~~~~
When checking right hand side of h2 with expected type
f (S (q + 1)) = case f (q + 1) of (k, r) => (S k, r)
Type mismatch between
case f (plus q 1) of (k, r) => (S k, r) = case f (plus q 1) of (k, r) => (S k, r) (Type of Refl)
and
case f (plus q 1) of (k, r) => (S k, r) = case f (plus q 1) of (k, r) => (S k, r) (Expected type)
Specifically:
Type mismatch between
case f (plus q 1) of
(k, r) => (S k, r)
and
case f (plus q 1) of
(k, r) => (S k, r)
Aren't the two mismatching terms identical? Why couldn't be constructed with Refl?

Can I implement Eq for a type which can contain a list of itself?

This code doesn't compile:
data Foo = A String | B (List Foo)
Eq Foo where
(==) (A x) (A y) = x == y
(==) (B xs) (B ys) = xs == ys
(==) _ _ = False
It yields the following error:
Type checking ./eq.idr eq.idr:11:3-27: | 11 | (==) (A x) (A y) =
x == y | ~~~~~~~~~~~~~~~~~~~~~~~~~ Prelude.Interfaces.Main.Foo
implementation of Prelude.Interfaces.Eq, method == is possibly not
total due to recursive path Prelude.Interfaces.Main.Foo implementation
of Prelude.Interfaces.Eq, method == --> Prelude.Interfaces.Main.Foo
implementation of Prelude.Interfaces.Eq, method ==
So is the problem here that we're relying on Eq Foo in its implementation, hence the recursive path? That doesn't seem to explain it, because this compiles:
data Bar = C String | D Bar
Eq Bar where
(==) (C x) (C y) = x == y
(==) (D x) (D y) = x == y
(==) _ _ = False
So - I can have recursive calls to == on whatever I'm defining the implementation on, but I can't to lists of it? Am I missing a trick to make this work, or am I trying to do something that's fundamentally broken somewhere?
The function that decides equality needs to be implemented in terms of mutual recursion, just as Foo itself is defined by mutual recursion.
Eq Foo where
(==) = eq
where mutual -- massive indentation necessary
eq : Foo -> Foo -> Bool
eq (A l) (A r) = l == r
eq (B l) (B r) = eq1 l r
eq _ _ = False
eq1 : List Foo -> List Foo -> Bool
eq1 (l :: ls) (r :: rs) = eq l r && eq1 ls rs
eq1 [] [] = True
eq1 _ _ = False
You can't reuse List's own (==), but it is possible to factor out a pattern.
zipWithFoldrElem : (ls : List a) -> (rs : List a) -> ((l : a) -> (r : a) -> Elem (l, r) (zip ls rs) -> b) -> (b -> Lazy b -> b) -> b -> b -> b -> b
zipWithFoldrElem [] [] _ _ e _ _ = e
zipWithFoldrElem [] (_ :: _) _ _ _ el _ = el
zipWithFoldrElem (_ :: _) [] _ _ _ _ er = er
zipWithFoldrElem (l :: ls) (r :: rs) f g e el er = f l r Here `g` zipWithFoldLazyElem ls rs (\l, r, e => f l r (There e)) g e el er
Eq Foo where
(A l) == (A r) = l == r
(B l) == (B r) = zipWithFoldrElem l r (f l r) (&&) True False False
where f : (ls : List Foo) -> (rs : List Foo) -> (l : Foo) -> (r : Foo) -> Elem (l, r) (zip ls rs) -> Bool
f (l :: _) (r :: _) l r Here = l == r
f (_ :: ls) (_ :: rs) l r (There e) = f ls rs l r e
f [] [] _ _ _ impossible
_ == _ = False
And, for show, here's a lexicographic Ord:
Ord Foo where
compare (A l) (A r) = l `compare` r
compare (B l) (B r) = zipWithFoldrElem l r (f l r) thenCompare EQ LT GT
where f : (ls : List Foo) -> (rs : List Foo) -> (l : Foo) -> (r : Foo) -> Elem (l, r) (zip ls rs) -> Ordering
f (l :: _) (r :: _) l r Here = l `compare` r
f (_ :: ls) (_ :: rs) l r (There e) = f ls rs l r e
f [] [] _ _ _ impossible
compare (A _) (B _) = LT
compare (B _) (A _) = GT
There's a much nicer way, now that I've grokked WellFounded a bit.
This data type is to Foo as Elem is to List. It tells you where to find a sub-Foo in a Foo.
-- s is smaller than b if either ...
data Smaller : (s : Foo) -> (b : Foo) -> Type where
-- it is one of the elements of ss when b = B ss
Surface : Elem s ss -> Smaller s (B ss)
-- it is smaller than one of the elements of ms when b = B ms
-- "m" is for "medium"
Deeper : Smaller s m -> Elem m ms -> Smaller s (B ms)
Smaller is WellFounded:
WellFounded Smaller where
wellFounded x = Access (acc x)
where mutual
acc : (b : Foo) -> (s : Foo) -> Smaller s b -> Accessible Smaller s
acc (B ss) s (Surface e) = accSurface ss s e
acc (B ms) s (Deeper {m} sr e) = accDeeper ms m e s sr
accSurface : (ss : List Foo) -> (s : Foo) -> Elem s ss -> Accessible Smaller s
accSurface (s :: _) s Here = Access (acc s)
accSurface (_ :: ss) s (There e) = accSurface ss s e
accDeeper : (ms : List Foo) -> (m : Foo) -> Elem m ms -> (s : Foo) -> Smaller s m -> Accessible Smaller s
accDeeper (m :: _) m Here s sr = acc m s sr
accDeeper (_ :: ms) m (There e) s sr = accDeeper ms m e s sr
This uses mutual recursion, just like my older answer, but it abstracts it away much more cleanly. The general skeleton of a WellFounded instance is:
WellFounded (rel : a -> a -> Type) where -- rel s b means s is smaller than b
wellFounded x = Access (acc x)
where acc : (b : a) -> (s : a) -> rel s b -> Accessible rel s
-- Accessible is really cryptic:
-- Access : (rec : (y : a) -> rel y x -> Accessible rel y) -> Accessible rel x
-- but the idea of acc is simple:
-- we convince the totality checker s is really smaller than b
-- acc needs to be recursive, and when it convinces the totality
-- checker, it can end with Access (acc s)
WellFounded buys us
wfRec : WellFounded rel =>
(step : (x : a) ->
(rec : (y : a) -> rel y x -> b) ->
b
) ->
a -> b
step is a function defined by open recursion. step gets an argument rec, and, instead of recursing to itself, step calls rec with a proof that the argument it's recursing on is the right size, and wfRec routes the call back to step (essentially it's fix : (step : (rec : (a -> b)) -> (x : a) -> b) -> a -> b; fix f x = f (fix f) x but total.)
We can now, cleanly, factor out the logic of (==) on lists:
eqBy : (ls : List a) -> (rs : List a) -> ((l : a) -> (r : a) -> (el : Elem l ls) -> (er : Elem r rs) -> Bool) -> Bool
eqBy (l :: ls) (r :: rs) eq = eq l r Here Here && eqBy ls rs (\l, r, el, er => eq l r (There el) (There er))
eqBy [] [] _ = True
eqBy _ _ _ = False
And the Eq instance is not much worse than the naive one:
Eq Foo where
(==) = wfRec step
where step : (x : Foo) -> ((y : Foo) -> Smaller y x -> Foo -> Bool) -> Foo -> Bool
step (A l) _ (A r) = l == r
step (B l) rec (B r) = eqBy l r (\l, r, el, er => rec l (Surface el) r)
step _ _ _ = False
eqBy and the WellFounded instance are now much more reusable than the zipWithFoldrElem abomination I previously created.

Idris - Can I express that two type parameters are equal in a pattern match?

Lets say I have the following
data Expr : Type -> Type where
Lift : a -> Expr a
Add : Num a => Expr a -> Expr a -> Expr a
Cnst : Expr a -> Expr b -> Expr a
data Context : Type -> Type where
Root : Context ()
L : Expr w -> Context x -> Expr y -> Expr z -> Context w
R : Expr w -> Context x -> Expr y -> Expr z -> Context w
M : Expr w -> Context x -> Expr y -> Expr z -> Context w
data Zipper : Type -> Type -> Type where
Z : Expr f -> Context g -> Zipper f g
E : String -> Context g -> Zipper String ()
I would like to write a function to rebuild a Zipper if I'm going up one level in the expression tree. Something like:
total
ZipUp : Zipper focus parent -> Type
ZipUp (Z e (R (Cnst {a} e1 e2) {x} c t u)) = Zipper a x
ZipUp (Z {f} e (L (Cnst l r) {x} c t u)) = Zipper f x
ZipUp (Z e (R (Add {a} e1 e2) {x} c t u)) = Zipper a x
ZipUp (Z {f} e (L (Add e1 e2) {x} c t u)) = Zipper f x
ZipUp _ = Zipper String ()
the problem comes when I want to write the function to return a ZipUp
up : (x : Zipper focus parent) -> ZipUp x
up (Z e (R (Cnst l r) c x y)) = Z (Cnst l e) c
up (Z e (L (Cnst l r) c x y)) = Z (Cnst e r) c
up (Z e (R (Add l r) c x y)) = Z (Add l e) c
up (Z e (L (Add l r) c x y)) = Z (Add e r) c
up (Z e (R (Lift x) c l r)) = E "Some error" c
up (Z e (L (Lift x) c l r)) = E "Some error" c
up (E s c) = E s c
This fails to typecheck on the Add case, because it can't infer that focus (type of e) matches with parent (expected type)
So my question has two parts then.
What can I do to express this relationship?
(that if the Zipper is an R constructed, e has the same type as r, or that e has the same type as l in the L constructed case. I've tried using {e = l} and other variants of this, but to no avail.)
The the code typechecks and runs if I comment out the last for lines of up to finish with:
up : (x : Zipper focus parent) -> ZipUp x
up (Z e (R (Cnst l r) c x y)) = Z (Cnst l e) c
up (Z e (L (Cnst l r) c x y)) = Z (Cnst e r) c
but the actual manipulation of the types should be the same in the Add case, yet this fails to typecheck, why is that?
Thanks for taking the time to read and/or answer!
This fails to typecheck on the Add case, because it can't infer that focus (type of e) matches with parent (expected type)
Because this is not always the case, e.g.
*main> :t Z (Lift "a") (R (Add (Lift 1) (Lift 2)) Root (Lift 4) (Lift 8))
Z (Lift "a") (R (Add (Lift 1) (Lift 2)) Root (Lift 4) (Lift 8)) : Zipper String Integer
And Add (Lift 1) (Lift "a") doesn't work because of the Num a constraint.
What can I do to express this relationship?
If you want to express the relationship within up: You have e : Expr f and can say that the same f should be used in the Add case:
up (Z {f} e (R (Add l r {a=f}) c x y)) = Z (Add l e) c
up (Z {f} e (L (Add l r {a=f}) c x y)) = Z (Add e r) c
up (Z e (R (Add l r) c x y)) = ?whattodo_1
up (Z e (L (Add l r) c x y)) = ?whattodo_2
Now you have a non total function because of the cases where a != f. I don't quite what you want to do, so I can't offer an option. :-)
If you want to express the relationship in Zipper you could do (very roughly) something like:
data Context : Bool -> Type -> Type where
Root : Context False ()
L : Expr w -> Context b x -> Expr y -> Expr z -> Context False w
R : Expr w -> Context b x -> Expr y -> Expr z -> Context True w
M : Expr w -> Context b x -> Expr y -> Expr z -> Context False w
data Zipper : Type -> Type -> Type where
Z : Expr f -> Context False g -> Zipper f g
ZR : Expr f -> Context True f -> Zipper f f
E : String -> Context b g -> Zipper String ()
Now you construct a proof when building up a zipper that f = g in a R-Context. Again, I cannot be specific, but I hope it helps in some way.

Idris determining result vector length

In Idris, if I want to remove an element based on predicate, there is filter, dropWhile, takeWhile. However, all these functions return a dependent pair (n : Nat ** Vect n elem).
Is there any function that return back as a Vect type?
For what I could think of:
Convert a dependent pair to Vect
Implement a type that indicate the length vector after transformation (thought I have no idea how), like Here, There
For above ideas, it seems quite cumbersome for 1 (convert every result) or 2 (design each of the type to indicate the result vector length).
Are there any better ways to achieve such behaviour?
dropElem : String -> Vect n String -> Vect ?resultLen String
Maybe this is what you are searching for?
import Data.Vect
count: (ty -> Bool) -> Vect n ty -> Nat
count f [] = 0
count f (x::xs) with (f x)
| False = count f xs
| True = 1 + count f xs
%hint
countLemma: {v: Vect n ty} -> count f v `LTE` n
countLemma {v=[]} = LTEZero
countLemma {v=x::xs} {f} with (f x)
| False = lteSuccRight countLemma
| True = LTESucc countLemma
filter: (f: ty -> Bool) -> (v: Vect n ty) -> Vect (count f v) ty
filter f [] = []
filter f (x::xs) with (f x)
| False = filter f xs
| True = x::filter f xs
Then you con do this:
dropElem: (s: String) -> (v: Vect n String) -> Vect (count ((/=) s) v) String
dropElem s = filter ((/=) s)
You can even reuse the existing filter implementation:
count: (ty -> Bool) -> Vect n ty -> Nat
count f v = fst $ filter f v
filter: (f: ty -> Bool) -> (v: Vect n ty) -> Vect (count f v) ty
filter f v = snd $ filter f v

Why doesn't equality involving “minus” typecheck in Idris?

Why won't the following typecheck:
minusReduces : (n : Nat) -> n `minus` Z = n
minusReduces n = Refl
Yet this will typecheck fine:
plusReduces : (n : Nat) -> Z `plus` n = n
plusReduces n = Refl
minus n doesn't reduce because minus is defined with pattern matching on the first argument:
total minus : Nat -> Nat -> Nat
minus Z right = Z
minus left Z = left
minus (S left) (S right) = minus left right
So you'll need to split your Z and S n cases as well:
minusReduces : (n : Nat) -> n `minus` Z = n
minusReduces Z = Refl
minusReduces (S k) = Refl