I am compiling the following simple program using Idris2.
import Data.Fin
%default total
negate : {k:_} -> Fin k -> Fin k
subt : {k:_} -> Fin k -> Fin k -> Fin k
add : {k:_} -> Fin k -> Fin k -> Fin k
mult : {k:_} -> Fin k -> Fin k -> Fin k
mult FZ b = FZ
mult (FS a) b = add b $ mult (weaken a) b
However, the compiler spits an error:
Error: mult is not total, possibly not terminating due to recursive
path Main.mult -> Main.mult -> Main.mult
Isn't the recursive call on input a which is smaller than (FS a)? Why is the totality check failing?
Thanks!
I don't know why the compiler doesn't realize that weaken a is smaller than FS a, although I suspect that the problem is weaken.
You can work around it by asserting that weaken a is smaller than FS a:
module Misc
import Data.Fin
%default total
add : Fin k -> Fin k -> Fin k
add a b = ?add_rhs
mult : Fin k -> Fin k -> Fin k
mult FZ _ = FZ
mult a#(FS a') b = add b $ mult (assert_smaller a (weaken a')) b
Do note that under the usual definition of addition and multiplication on integers, the result could be larger than k. I assume your add implementation will take care of this.
Related
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
I'm a green hand with Idris,and get confused with this definition, as I don't understand how it works.
The definitionare as follows.
sameS : (k : Nat)->(j : Nat)->(k = j)->((S k) = (S j))
sameS x x Refl=Refl
Let us start by breaking down the type signature:
sameS : (k : Nat) -> (j : Nat) -> (k = j) -> ((S k) = (S j))
sameS is a function.
sameS take the following arguments:
(k : Nat) a parameter k of type Nat
(j : Nat) a parameter j of type Nat
(k = j) A proof that k and j are equal
sameS returns:
((S k) = (S j)) proof that S k and S j are equal.
Now let us breakdown the definition:
sameS x x Refl = Refl
The type of Refl is a = a.
x is both the first and second argument because both are identical. We know this because the 3rd argument is Refl.
Refl is returned because S x = S x.
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.
I am working through Chapter 8 Type Driven Development with Idris, and I have a question about how rewrite interacts with Refl.
This code is shown as an example of how rewrite works on an expression:
myReverse : Vect n elem -> Vect n elem
myReverse [] = []
myReverse {n = S k} (x :: xs)
= let result = myReverse xs ++ [x] in
rewrite plusCommutative 1 k in result
where plusCommutative 1 k will look for any instances of 1 + k and replace it with k + 1.
My question is with this solution to rewriting plusCommutative as part of the exercies as myPlusCommutes with an answer being:
myPlusCommutes : (n : Nat) -> (m : Nat) -> n + m = m + n
myPlusCommutes Z m = rewrite plusZeroRightNeutral m in Refl
myPlusCommutes (S k) m = rewrite myPlusCommutes k m in
rewrite plusSuccRightSucc m k in Refl
I am having trouble with this line:
myPlusCommutes Z m = rewrite plusZeroRightNeutral m in Refl
because from what I can understand by using Refl on its own in that line as such:
myPlusCommutes Z m = Refl
I get this error:
When checking right hand side of myPlusCommutes with expected type
0 + m = m + 0
Type mismatch between
plus m 0 = plus m 0 (Type of Refl)
and
m = plus m 0 (Expected type)
Specifically:
Type mismatch between
plus m 0
and
m
First off, one thing I did not realize is that it appears Refl works from the right side of the = and seeks reflection from that direction.
Next, it would seem that rewriting Refl results in a change from plus m 0 = plus m 0 to m = plus m 0, rewriting from the left but stopping after the first replacement and not going to so far as to replace all instances of plus m 0 with m as I would have expected.
Ultimately, that is my question, why rewriting behaves in such a way. Is rewriting on equality types different and in those cases rewrite only replaces on the left side of the =?
To understand what is going on here we need to take into account the fact that Refl is polymorphic:
λΠ> :set showimplicits
λΠ> :t Refl
Refl : {A : Type} -> {x : A} -> (=) {A = A} {B = A} x x
That means Idris is trying to ascribe a type to the term Refl using information from the context. E.g. Refl in myPlusCommutes Z m = Refl has type plus m 0 = plus m 0. Idris could have picked the LHS of myPlusCommutes' output type and tried to ascribe the type m = m to Refl. Also you can specify the x expression like so : Refl {x = m}.
Now, rewrite works with respect to your current goal, i.e. rewrite Eq replaces all the occurrences of the LHS of Eq with its RHS in your goal, not in some possible typing of Refl.
Let me give you a silly example of using a sequence of rewrites to illustrate what I mean:
foo : (n : Nat) -> n = (n + Z) + Z
foo n =
rewrite sym $ plusAssociative n Z Z in -- 1
rewrite plusZeroRightNeutral n in -- 2
Refl -- 3
We start with goal n = (n + Z) + Z, then
line 1 turns the goal into n = n + (Z + Z) using the law of associativity, then
line 2 turns the current goal n = n + Z (which is definitionally equal to n = n + (Z + Z)) into n = n
line 3 provides a proof term for the current goal (if we wanted to be more explicit, we could have written Refl {x = n} in place of Refl).
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