我可以从枚举表达式中提取边界证明吗?

时间:2019-09-10 10:33:46

标签: proof idris

考虑这个简单的程序:

module Study

g : Nat -> Nat -> Nat
g x y = x - y

f : Nat -> List Nat
f x = map (g x) [1, 2 .. x]

它给出了一个明显的错误:

  |
4 | g x y = x - y
  |           ^
When checking right hand side of g with expected type
        Nat

When checking argument smaller to function Prelude.Nat.-:
        Can't find a value of type 
                LTE y x

—说我应该提供一些证明,证明这种减法是安全的。

当然,在给定的上下文中,g总是被安全地调用。这是从枚举的行为得出的。如何提取该事实的证明,以便可以将其用于g的调用?

我知道我可以使用isLTE来获得证明:

g : Nat -> Nat -> Nat
g x y = case y `isLTE` x of
             (Yes prf)   => x - y
             (No contra) => ?s_2

这实际上是我所知道的唯一方法,而且在我看来,在这种情况下,如果x≥y通过构造构成,应该有一种避免多余的案例陈述的方法。有吗?

1 个答案:

答案 0 :(得分:1)

对于map (\y = x - y) [1, 2 .. x]\y => LTE y x的每个元素都必须有一个证明[1, 2 .. x]。为此,有Data.List.Quantifiers.AllAll (\y => LTE y x) [1, 2 .. x]

但是构造和应用该证明并不是那么简单。您可以构建有关范围函数lteRange : (x : Nat) -> All (\y => LTE y x) (natRange x)的证明,也可以定义一个返回范围及其证明lteRange : (x : Nat) -> (xs : List Nat ** All (\y => LTE y x) xs)的函数。为简单起见,我将展示第二种类型的示例。

import Data.List.Quantifiers

(++) : All p xs -> All p ys -> All p (xs ++ ys)
(++) []        ys = ys
(++) (x :: xs) ys = x :: (xs ++ ys)

lteRange : (x : Nat) -> (xs : List Nat ** All (\y => LTE y x) xs)
lteRange Z = ([] ** [])
lteRange (S k) = let (xs ** ps) = lteRange k in
  (xs ++ [S k] ** weakenRange ps ++ [lteRefl])
  where
    weakenRange : All (\y => LTE y x) xs -> All (\y => LTE y (S x)) xs
    weakenRange []       = []
    weakenRange (y :: z) = lteSuccRight y :: weakenRange z

此外,map仅应用一个参数,但是(-)也需要证明。因此,有了一点辅助功能……

all_map : (xs : List a) -> All p xs -> (f : (x : a) -> p x -> b) -> List b
all_map [] [] f = []
all_map (x :: xs) (p :: ps) f = f x p :: all_map xs ps f

我们可以在运行时大致检查您想要做的事情而无需检查LTE

f : Nat -> List Nat
f x = let (xs ** prfs) = lteRange x in all_map xs prfs (\y, p => x - y)