关于功能的证明取决于其替代品的排序

时间:2016-06-29 09:46:31

标签: pattern-matching dependent-type idris theorem-proving

在Haskell有相当多的经验,我最近才开始使用Idris进行定理证明。这是一个最小的例子,它说明了我在尝试证明相当简单的语句时遇到的问题。

考虑我们有一个总函数test

total test : Integer -> Integer
test 1 = 1
test n = n

当然我们看到函数可以简化为test n = n,但让我们证明一下。我只是简单地讨论所有案件:

total lemma_test : (n : Integer) -> test n = n
lemma_test 1 = Refl
lemma_test n = Refl

但是,这不是类型检查:

Type mismatch between
        n = n (Type of Refl) and
        test n = n (Expected type)

Specifically:
        Type mismatch between
                n
        and
                test n

所以,问题似乎是Idris无法推断lemma_test的{​​{1}}不等于n的第二种情况,以及1的第二种情况必须应用。

当然,我们可以尝试明确列出所有案例,这些案件可能很麻烦,也可能不可能,如test s:

Integer

有没有办法为未在有限的数据构造函数集上定义的函数证明这样的语句,而是依赖于模式匹配从上到下工作的事实,例如本例中的total lemma_test : (n : Integer) -> test n = n lemma_test 1 = Refl lemma_test 2 = Refl lemma_test 3 = Refl ...

考虑到像这样的函数经常发生,也许我只是看不到一个相当简单的解决方案。

3 个答案:

答案 0 :(得分:2)

正如其他人所说,Integer是原始的,而不是归纳定义的Idris类型,因此我们不能对其进行详尽的模式匹配。更具体地说,问题在于Idris(实际上也是最先进的Agda!)我们无法真正证明“默认”模式匹配的事情,因为它们不包含有关所有先前模式的信息没能匹配。在我们的案例中,test n = 1未向我们提供n不等于1的证据。

通常的解决方案是使用可判定的相等(Boolean相等也可以是好的)而不是落空:

import Prelude

%default total

test : Integer -> Integer
test n with (decEq n 1)
  test n | Yes p = 1
  test n | No  p = n

lemma_test : (n : Integer) -> (test n) = n
lemma_test n with (decEq n 1)
 lemma_test _ | (Yes Refl)  = Refl
 lemma_test n | (No contra) = Refl

此处,No结果带有关于失败匹配的明确证据。

答案 1 :(得分:1)

我不确定Integer是如何定义的,或者如何对其进行归纳等等,所以这不是你问题的完整答案;但也许Nat版本也会为您提供信息? (也许,你真的可能意味着Nat,因为在你的第二个例子中你只列举了积极的自然?)

如果您更改test以使用Nat s:

total test : Nat -> Nat
test (S Z) = 1
test n = n

然后你可以在lemma_test中进行详尽的模式匹配:

total lemma_test : (n : Nat) -> test n = n
lemma_test (S Z) = Refl
lemma_test Z = Refl
lemma_test (S (S k)) = Refl

答案 2 :(得分:1)

Integer并未在Idris中定义,而是遵循GMP重要性。它对Idris实际上是不透明的,显然不是你能以这种方式在编译时解释的情况。通过归纳定义的类似Nat的内容,您可以以基本案例和递归案例的形式讨论证明。

关于n不是test n的类型错误告诉您,Idris无法减少表达式test n。我不确定它应该如何表现 - 显然它是一个完整的功能,并且它应该减少总功能。也许这与Integer对伊德里斯的不透明度有关?

您可以通过引入自由变量作为labmda参数来测试repl的减少量。例如。 \n => test n只回显\n => test n : Integer -> Integer(没有任何更改),但是,如果您从定义中移除test 1 = 1案例并再试一次,它会回复\n => n : Integer -> Integer - 它&#39 ;将test n缩减为n。然后你的证明就会按原样运作。