伊德里斯的非零整数类型?

时间:2018-01-19 16:23:10

标签: types idris

我有一个函数返回一个非零的整数,并希望通过它的返回类型来保证。你如何在伊德里斯中表达非零整数的类型?

1 个答案:

答案 0 :(得分:2)

根据您的功能,有不同的方式。如果您使用Nat作为返回类型,则可以阅读Theorem Proving in the Idris Tutorial。一个示例是inc增加Nat和证明incNotZ,每n : NatNot (inc n = Z)增加一次:

inc : Nat -> Nat
inc n = S n

incNotZ : (n : Nat) -> Not (Z = inc n)
incNotZ n p = replace {P = incNotZTy} p ()
  where
    incNotZTy : Nat -> Type
    incNotZTy Z = ()
    incNotZTy (S k) = Void

有时您可以在结果旁边生成证据,例如:

data NotZero : Nat -> Type where
  MkNotZero : (n : Nat) -> NotZero (S n)

inc : (n : Nat) -> NotZero (S n)
inc n = MkNotZero n

rev : NotZero n -> Not (n = 0)
rev (MkNotZero n) = SIsNotZ -- from Prelude.Nat

此处NotZero n证明n不为零,因为n只能通过(S n)构建。事实上,可以使用NotZero n将任何Not (n = 0)转换为rev

如果您的证明类型适合该功能,这通常是更好的选择。由于incNotZero都有(n : Nat) -> … (S n),您可以免费获得证明。另一方面,如果你想证明函数的某些特性,它所具有的属性,如plus的交换性或对称性,则需要第一种方法。

如果您使用Int作为返回类型,这通常不会有用,因为Int可能会溢出而且Idris无法争论Int(或IntegerFloat或......):

*main> 10000000000000000000 * (the Int 5)
-5340232221128654848 : Int

所以通常的方法是在运行时构建一个证明来查看非zeroness是否成立:

inc' : Int -> Int
inc' i = abs i + 1

incNotZ' : (i : Int) -> Either (So (inc' i == 0)) (So (not (inc' i == 0)))
incNotZ' i = choose (inc' i == 0)

然后当您调用incNotZ'时,您可以匹配结果以获得右侧的证据或处理左侧的错误案例。

如果您使用的是非溢出的Integer并且确实非常确定您的函数永远不会返回0,那么您可以强制编译器相信您:

inc' : Integer -> Integer
inc' i = abs i + 1

incNotZ' : (i : Integer) -> Not (0 = inc' i)
incNotZ' i = believe_me