module Prelude.Fin
import Prelude.Nat
import Prelude.Either
data Fin : Nat -> Type where
fZ : Fin (S k)
fS : Fin k -> Fin (S k)
instance Eq (Fin n) where
(==) fZ fZ = True
(==) (fS k) (fS k') = k == k'
(==) _ _ = False
finToNat : Fin n -> Nat -> Nat
finToNat fZ a = a
finToNat (fS x) a = finToNat x (S a)
instance Cast (Fin n) Nat where
cast x = finToNat x Z
finToInt : Fin n -> Integer -> Integer
finToInt fZ a = a
finToInt (fS x) a = finToInt x (a + 1)
instance Cast (Fin n) Integer where
cast x = finToInt x 0
weaken : Fin n -> Fin (S n)
weaken fZ = fZ
weaken (fS k) = fS (weaken k)
strengthen : Fin (S n) -> Either (Fin (S n)) (Fin n)
strengthen {n = S k} fZ = Right fZ
strengthen {n = S k} (fS i) with (strengthen i)
strengthen (fS k) | Left x = Left (fS x)
strengthen (fS k) | Right x = Right (fS x)
strengthen f = Left f
last : Fin (S n)
last {n=Z} = fZ
last {n=S _} = fS last
total fSinjective : {f : Fin n} -> {f' : Fin n} -> (fS f = fS f') -> f = f'
fSinjective refl = refl
-- Construct a Fin from an integer literal which must fit in the given Fin
natToFin : Nat -> (n : Nat) -> Maybe (Fin n)
natToFin Z (S j) = Just fZ
natToFin (S k) (S j) with (natToFin k j)
| Just k' = Just (fS k')
| Nothing = Nothing
natToFin _ _ = Nothing
integerToFin : Integer -> (n : Nat) -> Maybe (Fin n)
integerToFin x n = if x >= 0 then natToFin (cast x) n else Nothing
data IsJust : Maybe a -> Type where
ItIsJust : IsJust {a} (Just x)
fromInteger : (x : Integer) ->
{default (ItIsJust _ _)
prf : (IsJust (integerToFin x n))} -> Fin n
fromInteger {n} x {prf} with (integerToFin x n)
fromInteger {n} x {prf = ItIsJust} | Just y = y