packages feed

recover-rtti-0.3.0.0: src/Debug/RecoverRTTI/Nat.hs

{-# LANGUAGE DataKinds            #-}
{-# LANGUAGE GADTs                #-}
{-# LANGUAGE PolyKinds            #-}
{-# LANGUAGE ScopedTypeVariables  #-}
{-# LANGUAGE TypeFamilies         #-}
{-# LANGUAGE TypeOperators        #-}

-- | Inductive type-level natural numbers
module Debug.RecoverRTTI.Nat (
    -- * Type-level natural numbers
    Nat(..)
  , SNat(..)
  , KnownNat(..)
  , natVal
    -- * Type level functions computing natural numbers
  , Length
  ) where

{-------------------------------------------------------------------------------
  Natural numbers
-------------------------------------------------------------------------------}

-- | Natural numbers
--
-- Intended to be used lifted to the type level; unlike @ghc@'s type level
-- natural numbers, these are inductive.
data Nat = Z | S Nat

-- | Singleton for 'Nat'
data SNat (n :: Nat) where
  SZ :: SNat 'Z
  SS :: SNat n -> SNat ('S n)

class KnownNat (n :: Nat) where
  singNat :: SNat n

instance               KnownNat 'Z     where singNat = SZ
instance KnownNat n => KnownNat ('S n) where singNat = SS singNat

natVal :: forall n proxy. KnownNat n => proxy n -> Int
natVal _ = go (singNat :: SNat n)
  where
    go :: forall m. SNat m -> Int
    go SZ     = 0
    go (SS n) = go n + 1

{-------------------------------------------------------------------------------
  Type-level functions computing natural numbers
-------------------------------------------------------------------------------}

type family Length (xs :: [k]) :: Nat where
  Length '[]       = 'Z
  Length (_ ': xs) = 'S (Length xs)