问题
The following declaration of vector cons
cons : a -> Vect n a -> Vect (n + 1) a
cons x xs = x :: xs
fails with the error
Type mismatch between
S n
and
plus n 1
while the following vector append
compiles and works
append : Vect n a -> Vect m a -> Vect (n + m) a
append xs ys = xs ++ ys
Why type-level plus
is accepted for the second case but not for the first. What's the difference?
回答1:
Why does x :: xs : Vect (n + 1) a
lead to a type error?
(+)
is defined by induction on its first argument so n + 1
is stuck (because n
is a stuck expression, a variable in this case).
(::)
is defined with the type a -> Vect m a -> Vect (S m) a
.
So Idris needs to solve the unification problem n + 1 =? S m
and because you have a stuck term vs. an expression with a head constructor these two things simply won't unify.
If you had written 1 + n
on the other hand, Idris would have reduced that expression down to S n
and the unification would have been successful.
Why does xs ++ ys : Vect (n + m) a
succeeds?
(++)
is defined with the type Vect p a -> Vect q a -> Vect (p + q) a
.
Under the assumption that xs : Vect n a
and ys : Vect m a
, you will have to solve the constraints:
Vect n a ?= Vect p a
(xs
is the first argument passed to(++)
)Vect m a ?= Vect q a
(ys
is the first argument passed to(++)
)Vect (n + m) a ?= Vect (p + q) a
(xs ++ ys
is the result ofappend
)
The first two constraints lead to n = p
and m = q
respectively which make the third constraint hold: everything works out.
Consider append : Vect n a -> Vect m a -> Vect (m + n) a
.
Notice how I have swapped the two arguments to (+)
in this one. You would then be a situation similar to your first question: after a bit of unification, you would end up with the constraint m + n ?= n + m
which Idris, not knowing that (+)
is commutative, would'nt be able to solve.
Solutions? Work arounds?
Whenever you can it is infinitely more convenient to have a function defined using the same recurrence pattern as the computation that happens in its type. Indeed when that is the case the type will be simplified by computation in the various branches of the function definition.
When you can't, you can rewrite
proofs that two things are equal (e.g. that n + 1 = S n
for all n
) to adjust the mismatch between a term's type and the expected one. Even though this may seem more convenient than refactoring your code to have a different recurrence pattern, and is sometimes necessary, it usually is the start of path full of pitfalls.
来源:https://stackoverflow.com/questions/45744130/plus-vs-s-in-a-function-type