我有一个函数返回一个非零的整数,并希望通过它的返回类型来保证。你如何在伊德里斯中表达非零整数的类型?
答案 0 :(得分:2)
根据您的功能,有不同的方式。如果您使用Nat
作为返回类型,则可以阅读Theorem Proving in the Idris Tutorial。一个示例是inc
增加Nat
和证明incNotZ
,每n : Nat
,Not (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
。
如果您的证明类型适合该功能,这通常是更好的选择。由于inc
和NotZero
都有(n : Nat) -> … (S n)
,您可以免费获得证明。另一方面,如果你想证明函数的某些特性,它所具有的属性,如plus
的交换性或对称性,则需要第一种方法。
如果您使用Int
作为返回类型,这通常不会有用,因为Int
可能会溢出而且Idris无法争论Int
(或Integer
或Float
或......):
*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