Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type of nonzero integers in Idris?

Tags:

types

idris

I have a function that returns an integer that should be nonzero, and would like to guarantee that through its return type. How do you express the type of nonzero integers in Idris?

like image 858
BlenderBender Avatar asked Sep 17 '25 06:09

BlenderBender


1 Answers

Depending on your function there are different ways. If you use Nat as return type, you could read about Theorem Proving in the Idris Tutorial. An example would be inc that increases a Nat and a proof incNotZ, that for every 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

Sometimes you can generate a proof alongside the result, f.e.:

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

Here NotZero n is a proof that n is not zero, as n can only be constructed via (S n). And indeed one can transform any NotZero n to Not (n = 0) with rev.

If your proof type fits the function this is often the better option. Because of both inc and NotZero having (n : Nat) -> … (S n) you get the proof for free. On the other hand, if you want to proof something about a function, what property it holds, like the commutativity or symmetry of plus, the first approach is needed.


If you are using Int as return type, this isn't usually useful, because Int can overflow and Idris can't argue about Int (or Integer or Float or …):

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

So the usual approach would be to construct a proof at runtime to see if the non-zeroness holds:

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)

Then when you call incNotZ' you can match on the result to get a proof on the right or handle the error case on the left.

If you are using for example non-overflowing Integer and are really, really sure that your function will never return a 0, you can force the compiler to believe you:

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

incNotZ' : (i : Integer) -> Not (0 = inc' i)
incNotZ' i = believe_me
like image 89
xash Avatar answered Sep 19 '25 16:09

xash