Search code examples
idris

Maintaining a Nat within a fixed range


I'd like to have a Nat that remains within a fixed range. I would like functions incr and decr that fail if they are going to push the number outside the range. This seems like it might be a good use case for Fin, but I'm not really sure how to make it work. The type signatures might look something like this:

- Returns the next value in the ordered finite set.
- Returns Nothing if the input element is the last element in the set. 
incr : Fin n -> Maybe (Fin n)

- Returns the previous value in the ordered finite set.
- Returns Nothing if the input element is the first element in the set.
decr : Fin n -> Maybe (Fin n)

The Nat will be used to index into a Vect n. How can I implement incr and decr? Is Fin even the right choice for this?


Solution

  • I guess the easiest way is to use some standard Fin↔Nat conversion functions from Data.Fin:

    incr, decr : {n : Nat} -> Fin n -> Maybe (Fin n)
    incr {n=n} f = natToFin (succ $ finToNat f) n
    
    decr {n=n} f = case finToNat f of
        Z => Nothing
        S k => natToFin k n