在函数类型中加上vs S.

时间:2017-08-17 20:08:20

标签: idris

以下向量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,而第一种情况不接受。有什么区别?

1 个答案:

答案 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 ays : Vect m a,您必须解决约束:

  • Vect n a ?= Vect p axs是传递给(++)的第一个参数)
  • Vect m a ?= Vect q ays是传递给(++)的第一个参数)
  • Vect (n + m) a ?= Vect (p + q) axs ++ ysappend
  • 的结果

前两个约束分别导致n = pm = q,这使第三个约束成立:一切正常。

考虑append : Vect n a -> Vect m a -> Vect (m + n) a

注意我在这一个中如何将两个参数交换为(+)。然后你就会出现类似于你的第一个问题的情况:经过一段时间的统一后,你最终会遇到约束m + n ?= n + m,而Idris,不知道(+)是可交换的,将无法解决。

解决方案?解决方法?

无论什么时候,使用与其类型中发生的计算相同的重复模式定义函数是非常方便的。实际上,在这种情况下,类型将通过函数定义的各个分支中的计算来简化。

如果你不能,你可以rewrite证明两件事情是平等的(例如,所有n + 1 = S n n)来调整术语类型与预期类型之间的不匹配。尽管这看起来比重构代码以使其具有不同的重复模式更方便,并且有时是必要的,但它通常是充满陷阱的路径的开始。