以下向量cons
cons : a -> Vect n a -> Vect (n + 1) a
cons x xs = x :: xs
失败并显示错误
Type mismatch between
S n
and
plus n 1
而以下向量append
编译并运行
append : Vect n a -> Vect m a -> Vect (n + m) a
append xs ys = xs ++ ys
为什么第二种情况接受类型级plus
,而第一种情况不接受。有什么区别?
答案 0 :(得分:6)
x :: xs : Vect (n + 1) a
会导致类型错误? (+)
由第一个参数的归纳定义,因此n + 1
被卡住(因为n
是一个卡住的表达式,在这种情况下是一个变量)。
(::)
的定义类型为a -> Vect m a -> Vect (S m) a
。
因此,Idris需要解决统一问题n + 1 =? S m
,因为你有一个卡住的术语而不是带有头部构造函数的表达式,这两件事根本就不会统一。
如果您曾写过1 + n
,那么Idris会将该表达式降低到S n
,并且统一会成功。
xs ++ ys : Vect (n + m) a
成功? (++)
的定义类型为Vect p a -> Vect q a -> Vect (p + q) a
。
假设xs : Vect n a
和ys : Vect m a
,您必须解决约束:
Vect n a ?= Vect p a
(xs
是传递给(++)
的第一个参数)Vect m a ?= Vect q a
(ys
是传递给(++)
的第一个参数)Vect (n + m) a ?= Vect (p + q) a
(xs ++ ys
是append
)前两个约束分别导致n = p
和m = q
,这使第三个约束成立:一切正常。
append : Vect n a -> Vect m a -> Vect (m + n) a
。注意我在这一个中如何将两个参数交换为(+)
。然后你就会出现类似于你的第一个问题的情况:经过一段时间的统一后,你最终会遇到约束m + n ?= n + m
,而Idris,不知道(+)
是可交换的,将无法解决。
无论什么时候,使用与其类型中发生的计算相同的重复模式定义函数是非常方便的。实际上,在这种情况下,类型将通过函数定义的各个分支中的计算来简化。
如果你不能,你可以rewrite
证明两件事情是平等的(例如,所有n + 1 = S n
n
)来调整术语类型与预期类型之间的不匹配。尽管这看起来比重构代码以使其具有不同的重复模式更方便,并且有时是必要的,但它通常是充满陷阱的路径的开始。