Idris "did not change type" 用于用完全相同的类型重写

Idris "did not change type" for rewrite with exact same type

Context 我正在尝试为 Vect 编写 ++ 的版本,其中编译器可以推断出结果 Vect 具有预期内容。

详细信息我正在努力了解为什么第二次重写不起作用

import Data.Vect
import Data.Nat

infixl 9 ++:

public export
(++:) : {0 r, r' : Nat} -> Vect r Nat -> Vect r' Nat -> Vect (r' + r) Nat
(++:) [] y = rewrite plusZeroRightNeutral r' in y
(++:) {r = S rr} (x :: xs) y = rewrite plusSuccRightSucc r' rr in x :: (xs ++: y)

我特意在签名中以相反的顺序添加了矢量长度,以使 API 更易于使用。我看到了

"tmp.idr" 8L, 254C written
Error: While processing right hand side of ++:. Rewriting by S (r' + rr) = r' + S rr did not change type Vect (r' + S rr) Nat.

/src/tmp.idr:8:32--8:82
   |
 8 | (++:) {r = S rr} (x :: xs) y = rewrite plusSuccRightSucc r' rr in x :: (xs ++: y)

我不明白为什么 r' + S rr 等于 S (r' + rr) 的证明不重写 r' + S rr。这是我没有 rewrite

时的错误
"tmp.idr" 8L, 219C written
Error: While processing right hand side of ++:. Can't solve constraint between: S (plus r' rr) and plus r' (S rr).

/src/tmp.idr:8:32--8:47
   |
 8 | (++:) {r = S rr} (x :: xs) y = x :: (xs ++: y)
   |                                ^^^^^^^^^^^^^^^

这很简单,因为 rewrite 以相反的顺序工作。所以如果目标是 goal 但你有 a,你需要证明 goal = a,而不是 a = goal。 (我发现这总是很混乱,因为背景中的 replace 需要 a = goal,但我猜这是因为 rewrite 重写了目标项。)因此 sym 这个应该工作:

(++:) {r = S rr} (x :: xs) y = rewrite sym $ plusSuccRightSucc r' rr in x :: (xs ++: y)