我和伊德里斯一起玩,我遇到了一些令我困惑的事情:
以下类型检查:
conc : Vect n a -> Vect m a -> Vect (n+m) a
conc [] ys = ys
conc (x :: xs) ys = x :: (conc xs ys)
但这并不是:
conc : Vect n a -> Vect m a -> Vect (m+n) a
conc [] ys = ys
conc (x :: xs) ys = x :: (conc xs ys)
出现以下错误:
When checking right hand side of conc with expected type
Vect (m + 0) a
Type mismatch between
Vect m a (Type of ys)
and
Vect (plus m 0) a (Expected type)
Specifically:
Type mismatch between
m
and
plus m 0
等效xs ++ ys类型检查,但是即使它们都匹配长度为n + m的类型定义,ys ++ xs也不会。
这让我感到惊讶,因为添加是可交换的。有什么我可以做的(可能有约束?)函数签名来获得xs ++ ys和ys ++ xs表达式类型检查?
答案 0 :(得分:8)
这是 Idris 中初学者混淆的常见话题。
第二个conc
版本中的问题:
conc : Vect n a -> Vect m a -> Vect (m+n) a
conc [] ys = ys
Idris 不能应用加法交换性,因为 Nat plus commutativity 是从编译器的角度来看的定理。这是它的类型:
Idris> :t plusCommutative
plusCommutative : (left : Nat) -> (right : Nat) -> left + right = right + left
没有一般规则可以告诉您选择和应用哪个定理。当然,可以针对一些简单的案例制定一些启发式方法,例如 Nat commutativity 。但这也可能使其他一些案例难以理解。
您需要考虑的另一件事是plus
:
Idris> :printdef plus
plus : Nat -> Nat -> Nat
plus 0 right = right
plus (S left) right = S (plus left right)
函数plus
以这样的方式定义,即在第一个参数上进行模式匹配。 Idris 实际上可以在类型中执行此模式匹配。所以在第一个版本中,
conc : Vect n a -> Vect m a -> Vect (n+m) a
conc [] ys = ys
你的类型为(0 + m), Idris 可以用plus 0 m
替换m
以及所有类型的东西。如果您通过第二个参数上的模式匹配来定义plus m 0
运算符,+
将起作用。例如,这会编译:
infixl 4 +.
(+.) : Nat -> Nat -> Nat
n +. Z = n
n +. (S m) = S (n +. m)
conc : Vect n a -> Vect m a -> Vect (m +. n) a
conc [] ys = ys
conc (x :: xs) ys = x :: (conc xs ys)
但显而易见的是,为您需要的每个案例编写新的运算符都很糟糕。因此,为了使您的第二个版本可编辑,您应该在 Idris 中使用rewrite ... in
语法。你需要下一个定理:
Idris> :t plusZeroRightNeutral
plusZeroRightNeutral : (left : Nat) -> left + 0 = left
Idris> :t plusSuccRightSucc
plusSuccRightSucc : (left : Nat) -> (right : Nat) -> S (left + right) = left + S right
Idris> :t sym
sym : (left = right) -> right = left
这是编译的版本:
conc : Vect n a -> Vect m a -> Vect (m + n) a
conc {m} [] ys = rewrite plusZeroRightNeutral m in ys
conc {n=S k} {m} (x :: xs) ys = rewrite (sym $ plusSuccRightSucc m k) in x :: (conc xs ys)
我这里没有解释rewriting
和定理证明如何在这里起作用。如果您不了解某些内容,这是另一个问题的主题。但是你可以在教程中阅读(或者等待The Book release :)。