您如何在证明中对依赖对进行操作?

时间:2018-10-14 21:00:54

标签: idris

这是对this question的跟进。多亏了Kwartz,我现在有了一个命题状态,如果b除以a,然后b除以* c表示任意整数c,即:

alsoDividesMultiples : (a, b, c : Integer) ->
                       DivisibleBy a b ->
                       DivisibleBy (a * c) b

现在,目标是证明这一说法。我意识到我不了解如何对依赖对进行操作。我尝试了一个更简单的问题,该问题表明每个数字都可以被1整除。经过可耻的思考,我想到了 我想出了一个解决方案:

-- All numbers are divisible by 1.
DivisibleBy a 1 = let n = a in
  (n : Integer ** a = 1 * n)

这可以编译,但是我怀疑它是否有效。为了确认我错了,将其略微更改为:

-- All numbers are divisible by 1.
DivisibleBy a 1 = let n = a in
  (n : Integer ** a = 2 * n)

这也会编译,这意味着我的“英语”解释肯定是不正确的,因为我会将其解释为“所有数字都可以被一个整数整除,因为每个数字都是另一个整数的两倍”。因此,我不能完全确定我要用那句话说明什么。因此,我回过头来尝试了一种更常规的方式来说明问题:

oneDividesAll : (a : Integer) ->
                (DivisibleBy a 1)
oneDividesAll a = ?sorry

对于oneDividesAll的实现,我不太确定如何“注入” (n = a)的事实。例如,我将这种证明写成(英文):

  

我们希望证明1 |一种。如果是这样,则a = 1 * n会持续大约n。让n = a,然后a = a * 1,根据身份,这是正确的。

我不确定该如何说:“考虑n = a的时间”。据我了解,rewrite策略需要证明n = a

我试图改编我的谬论:

oneDividesAll : (a : Integer) ->
                (DivisibleBy a 1)
oneDividesAll a = let n = a in (n : Integer ** a = b * n)

但这给出了:

   |
12 | oneDividesAll a = let n = a in (n : Integer ** a = b * n)
   |                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When checking right hand side of oneDividesAll with expected type
        DivisibleBy a 1

Type mismatch between
        Type (Type of DPair a P)
and
        (n : Integer ** a = prim__mulBigInt 1 n) (Expected type)

任何帮助/提示将不胜感激。

1 个答案:

答案 0 :(得分:2)

首先,如果要证明数字的性质,则应使用Nat(或其他归纳类型)。 Integer使用的原语中,参数不能比prim__mulBigInt : Integer -> Integer -> Integer争论得更远;您传递两个Integer来获得一个。编译器不知道任何内容,结果Integer的样子如何,因此它无法证明其内容。

所以我将继续使用Nat

DivisibleBy : Nat -> Nat -> Type
DivisibleBy a b = (n : Nat ** a = b * n)

同样,这是一个命题,而不是证明。 DivisibleBy 6 0是有效类型,但找不到proof : Divisible 6 0。所以你说对了

oneDividesAll : (a : Nat) ->
                (DivisibleBy a 1)
oneDividesAll a = ?sorry

这样,您可以生成oneDividesAll a : DivisibleBy a 1形式的证明。那么,?sorry漏洞是什么? :t sorry给了我们sorry : (n : Nat ** a = plus n 0)(在DivisibleBy a 1看来,依德里斯可以解决)。您对这对的右侧感到困惑:x = y是一种类型,但是现在我们需要一个值-这是您最后一次错误隐式错误消息提示所基于的内容。 =只有一个构造函数Refl : x = x。因此,我们需要使相等的两边都具有相同的值,因此结果看起来像(n ** Refl)

如您所想,我们需要将n设置为a

oneDividesAll a = (a ** ?hole)

对于所需的重写策略,我们签出:search plus a 0 = a,并查看plusZeroRightNeutral的类型正确。

oneDividesAll a = (a ** rewrite plusZeroRightNeutral a in ?hole)

现在:t hole给了我们hole : a = a,所以我们可以自动完成到Refl

oneDividesAll a = (a ** rewrite plusZeroRightNeutral a in Refl)

Idris Doc中有一个很好的定理证明教程(其中还解释了为什么plus a Z不减少)。