In this answer on a question about the totality checker, a workaround involving using case
instead of with
was recommended.
However, in situations where the result of the match refines the type of other arguments, this transformation is not straightforward to make.
For example, given the following definitions:
data IsEven : Nat -> Nat -> Type where
Times2 : (n : Nat) -> IsEven (n + n) n
data IsOdd : Nat -> Nat -> Type where
Times2Plus1 : (n : Nat) -> IsOdd (S (n + n)) n
total parity : (n : Nat) -> Either (Exists (IsEven n)) (Exists (IsOdd n))
the following definition typechecks, but is not accepted as total:
foo1 : Nat -> Nat
foo1 n with (parity n)
foo1 n@(k + k) | Left (Evidence _ (Times2 k)) = (n * n)
foo1 n@(S (k + k)) | Right (Evidence _ (Times2Plus1 k)) = (2 * (k * n + k))
whereas the following one doesn't typecheck:
foo2 : Nat -> Nat
foo2 n = case parity n of
Left (Evidence k (Times2 k)) => n * n
Right (Evidence k (Times2Plus1 k)) => (2 * (k * n + k))
due to
Type mismatch between
IsEven (k + k) k (Type of Times2 k)
and
IsEven n k (Expected type)
I also tried expanding the with
in foo1
:
foo1' : (n : Nat) -> Either (Exists (IsEven n)) (Exists (IsOdd n)) -> Nat
foo1' n@(k + k) (Left (Evidence k (Times2 k))) = (n * n)
foo1' n@(S (k + k)) (Right (Evidence k (Times2Plus1 k))) = 2 * (k * n + k)
foo1 : Nat -> Nat
foo1 n = foo1' n (parity n)
but here, foo1'
is also not accepted as total:
foo1' is not total as there are missing cases