我在伊德里斯写了以下命题:
total
plusOneCommutes : (n : Nat) -> (m : Nat) -> (n + S m = S n + m)
plusOneCommutes Z k = Refl
plusOneCommutes (S k) j =
let inductiveHypothesis = plusOneCommutes k j in
rewrite inductiveHypothesis in Refl
使用来自Prelude.Nat
源代码的灵感,我理解为什么使用递归调用(在第二种情况下)作为归纳假设来证明这种情况是有意义的。但是,仔细阅读有关重写的详细信息,我并不真正理解其中发生的事情及其原因。
如果我写:
plusOneCommutes (S k) j = ?hole
我从编译器中得到以下内容:
- + HolyGrail.hole [P]
`-- k : Nat
j : Nat
------------------------------------------------------
HolyGrail.hole : S (plus k (S j)) = S (S (plus k j))
这看起来并不合适。根据{{1}}的签名,此洞应具有plusOneCommutes
类型。
如果我写的话,更进一步引入归纳假设:
(plus (S k) (S j)) = (plus (S (S k)) j)
然后plusOneCommutes (S k) j =
let inductiveHypothesis = plusOneCommutes k j in
?hole
的类型变为:
hole
然后使用 - + HolyGrail.hole [P]
`-- k : Nat
j : Nat
inductiveHypothesis : k + S j = S k + j
-------------------------------------------------------------------------
HolyGrail.hole : S (plus k (S j)) = S (S (plus k j))
inductiveHypothesis
导致 - + HolyGrail.hole [P]
`-- k : Nat
j : Nat
inductiveHypothesis : k + S j = S k + j
_rewrite_rule : k + S j = S k + j
-------------------------------------------------------------------------
HolyGrail.hole : (\replaced => S replaced = S (S (plus k j))) (S k + j)
这是预期的类型,而Idris可以使用S (plus (S k) j) = S (S (plus k j))
自动替换?hole
。
令我感到困惑的是,我从签名推断出的内容与编译器从洞中推断的内容之间的类型出乎意料的差异。如果我自愿引入错误:
我收到以下消息:
Refl
- + Errors (1)
`-- HolyGrail.idr line 121 col 16:
When checking right hand side of plusOneCommutes with expected type
S k + S j = S (S k) + j
Type mismatch between
S (S (plus k j)) = S (S (plus k j)) (Type of Refl)
and
S (plus k (S j)) = S (S (plus k j)) (Expected type)
Specifically:
Type mismatch between
S (plus k j)
and
plus k (S j)
部分与上述步骤一致,但不是Type mismatch...
部分,它给出了我期望的类型。
答案 0 :(得分:4)
以下编译器实际上是有道理的:
- + HolyGrail.hole [P]
`-- k : Nat
j : Nat
------------------------------------------------------
HolyGrail.hole : S (plus k (S j)) = S (S (plus k j))
在=
类型的左侧,您有n + S m
。在n
上进行模式匹配后,您有(S k)
,并且S k + S j
类型应为plus (S k) (S j)
。在this question中,我解释了一个重要的观点:从编写plus
函数的事实以及编译器可以在类型中执行模式匹配的事实,您只看到S (plus k (S j))
正在应用{ {1}}至plus
和(S k)
。与(S j)
类似的情况。
现在到S n + m
。在 Agda 编程语言中,rewrite
只是rewrite
上模式匹配的语法糖。有时你可以用 Idris 中的模式匹配替换Refl
,但在这种情况下不能。
我们可以尝试做类似的事情。考虑下一个:
rewrite
编译器说下一个非常合理的事情:
total
plusOneCommutes : (n : Nat) -> (m : Nat) -> (n + S m = S n + m)
plusOneCommutes Z k = Refl
plusOneCommutes (S k) j = case plusOneCommutes k j of
prf => ?hole
- + HolyGrail.hole [P]
`-- k : Nat
j : Nat
prf : k + S j = S k + j
------------------------------------------------------
HolyGrail.hole : S (plus k (S j)) = S (S (plus k j))
证明prf
是有道理的。使用k + S j = S k + j
后:
rewrite
我们得到了:
plusOneCommutes (S k) j = case plusOneCommutes k j of
prf => rewrite prf in ?hole
Idris 中的 - + HolyGrail.hole [P]
`-- k : Nat
j : Nat
prf : k + S j = S k + j
_rewrite_rule : k + S j = S k + j
-------------------------------------------------------------------------
HolyGrail.hole : (\replaced => S replaced = S (S (plus k j))) (S k + j)
的行为方式如下:
rewrite
个对象和Refl : left = right
。expr : t
中搜索left
。t
替换为left
中的right
。在我们的案例中:
t
是t
S (plus k (S j)) = S (S (plus k j))
Refl : plus k (S j) = plus (S k) j
是left
plus k (S j)
是right
plus (S k) j
(左)替换为plus k (S j)
中的plus (S k) j
(右),我们得到t
。 Idris可以执行模式匹配。而S (plus (S k) j) = S (S (plus k j))
自然会成为S (plus (S k) j)
。