简短回答
将类型签名更改为two : (xs : Vect n elem) -> Vect (n + n) elem
.
如果你真的需要这样
前往Vect (n * 2) elem
有点复杂。这里:
two' : Vect n elem -> Vect (n * 2) elem
two' {n} xs = rewrite multCommutative n 2 in rewrite plusZeroRightNeutral n in xs ++ xs
您收到该错误消息的原因是类型检查中的相等性是还原为正常形式后的相等性。n + n
and mult n 2
是相等的,但它们的正常形式却不相同。 (mult n 2
是什么n * 2
解析类型类后减少到。)
你可以看到定义mult
像这样:
*kevinmeredith> :printdef mult
mult : Nat -> Nat -> Nat
mult 0 right = 0
mult (S left) right = plus right (mult left right)
它通过第一个参数的模式匹配来工作。由于类型签名中的第一个参数two
is n
, mult
根本无法减少。multCommutative
将帮助我们扭转局面:
*kevinmeredith> :t multCommutative
multCommutative : (left : Nat) ->
(right : Nat) -> left * right = right * left
我们应用平等的最佳工具是rewrite
,就像我的定义一样two'
. (run :t replace
如果你想看看如何以困难的方式做到这一点,请在 REPL 中)rewrite foo in bar
建造,foo
是某种类型的东西a = b
and bar
具有外部表达式的类型,但与所有a
s 替换为b
s。在我的two'
上面我先用它来改变Vect (n * 2)
to Vect (2 * n)
。这让mult
减少。如果我们看一下mult
上面,并将其应用到2
i.e. S (S Z)
and n
, 你得到plus n (mult (S Z) n
, 进而plus n (plus n (mult Z n))
, 进而plus n (plus n Z)
。你不必自己计算出减少量,你可以应用重写并在末尾打一个洞:
two' : Vect n elem -> Vect (n * 2) elem
two' {n} xs = rewrite multCommutative n 2 in ?aaa
然后问伊德里斯:
*kevinmeredith> :t aaa
elem : Type
n : Nat
xs : Vect n elem
_rewrite_rule : plus n (plus n 0) = mult n 2
--------------------------------------
aaa : Vect (plus n (plus n 0)) elem
plus n Z
不减少,因为plus
由第一个参数的递归定义,就像mult
. plusZeroRightNeutral
为您提供所需的平等:
*kevinmeredith> :t plusZeroRightNeutral
plusZeroRightNeutral : (left : Nat) -> left + 0 = left
我使用了相同的技术rewrite
again.
:search
可以让你在图书馆中搜索特定类型的居民。您经常会发现有人已经为您完成了证明事情的工作。
*kevinmeredith> :s (n : Nat) -> n + 0 = n
= Prelude.Nat.multOneLeftNeutral : (right : Nat) ->
fromInteger 1 * right = right
= Prelude.Nat.plusZeroRightNeutral : (left : Nat) ->
left + fromInteger 0 = left
*kevinmeredith> :s (n, m : Nat) -> n * m = m * n
= Prelude.Nat.multCommutative : (left : Nat) ->
(right : Nat) -> left * right = right * left
(此答案适用于 Idris 版本 0.9.20.1)