证明索引在给定的列表边界内 (index + 1) 在边界内

Proving an index is within list bounds given (index + 1) is within bounds

假设我们有一个 list : List a,我们想使用它的第一个和第二个元素:

case inBounds 1 list of
     Yes prf => doSmth (index 0 list) (index 1 list)
     No _ => doSmthElse

不幸的是,这不会进行类型检查:确实,prfInBounds 1 list 成立的证明,但是虽然对我们人类来说很明显 InBounds 0 list 紧随其后,但它仍然需要显示给类型检查器。

当然可以写个辅助证明

inBoundsDecr : InBounds (S k) xs -> InBounds k xs
inBoundsDecr {k = Z} (InLater y) = InFirst
inBoundsDecr {k = (S k)} (InLater y) = InLater (inBoundsDecr y)

然后在 Yes 分支中像这样使用它:

case inBounds 1 list of
     Yes prf => let prf' = inBoundsDecr prf in
                    doSmth (index 0 list) (index 1 list)
     No _ => doSmthElse

不过好像比较冗长

那么,在 Idris 中最简洁 and/or 惯用的方法是什么?

如果你有 xs 的证明,可以提供一些关于 xs 的信息,最好使用 with 而不是 case。然后编译器可以看到参数可以通过证明来确定。本章教程见:Views and the "with" rule

addHs : List Nat -> Nat
addHs xs with (inBounds 1 xs)
  addHs xs | p = ?hole

Pattern-matching 在 p 上给出 Yes prf,然后是 Yes (InLater y),然后是 Yes (InLater InFirst),并将 xs 更新为 (x :: y :: xs) .因此您可以轻松使用 xy:

addHs : List Nat -> Nat
addHs xs with (inBounds 1 xs)
  addHs (x :: y :: xs) | (Yes (InLater InFirst)) = x + y
  addHs xs | (No contra) = 0

问题是——在这里它不能正常工作。如果您检查 addHs 是否总计,编译器会警告您,因为它认为可能会达到另一个 Yes (InLater p)。不知道为什么,完整性检查器不是那么好。但理论上它应该可以正常工作。 :-)

除了你最初的尝试(这可能更冗长,但你不太依赖完整性检查器),你当然可以添加一个虚拟 Yes (InLater p) 案例或停在那里做一些事情喜欢

addHs : List Nat -> Nat
addHs xs with (inBounds 1 xs)
  addHs (x :: xs) | (Yes (InLater prf)) = x + (index 0 xs)
  addHs xs | (No contra) = 0

或者有点不安全并断言该案例无法访问:

addHs : List Nat -> Nat
addHs xs with (inBounds 1 xs) proof q
  addHs (x :: y :: xs) | Yes (InLater InFirst) = x + y
  addHs (x :: xs) | Yes (InLater p) = assert_unreachable
  addHs xs | No _ = 0