{-# LANGUAGE DataKinds #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} {-# OPTIONS_GHC -fplugin GHC.TypeLits.KnownNat.Solver #-} module Nats where import Data.Proxy import Numeric.Natural import qualified GHC.TypeLits as G data Dict c a where Dict :: c a => Dict c a data Nat = Z | S Nat deriving (Show) data SNat n where SZ :: SNat Z SS :: SNat n -> SNat (S n) deriving instance Show (SNat n) class KnownNat n where knownNat :: SNat n instance KnownNat Z where knownNat = SZ instance KnownNat n => KnownNat (S n) where knownNat = SS knownNat unSNat :: SNat n -> Natural unSNat SZ = 0 unSNat (SS n) = 1 + unSNat n unNat :: Nat -> Natural unNat Z = 0 unNat (S n) = 1 + unNat n snatKnown :: SNat n -> Dict KnownNat n snatKnown SZ = Dict snatKnown (SS n) | Dict <- snatKnown n = Dict type family n + m where Z + m = m S n + m = S (n + m) type family GNat n where GNat Z = 0 GNat (S n) = 1 G.+ GNat n gknownNat :: KnownNat n => Proxy n -> Dict G.KnownNat (GNat n) gknownNat (Proxy @n) = go (knownNat @n) where go :: SNat m -> Dict G.KnownNat (GNat m) go SZ = Dict go (SS n) | Dict <- go n = Dict