{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Data.Type.Bin (
SBin (..), SBinP (..),
sbinToBin, BP.sbinpToBinP,
sbinToNatural, BP.sbinpToNatural,
SBinI (..), SBinPI (..),
withSBin, BP.withSBinP,
reify,
reflect,
reflectToNum,
eqBin,
induction,
Succ, Succ', Succ'',
withSucc,
Pred,
Plus,
Mult2, Mult2Plus1,
ToGHC, FromGHC,
ToNat, FromNat,
Bin0, Bin1, Bin2, Bin3, Bin4, Bin5, Bin6, Bin7, Bin8, Bin9,
) where
import Data.Bin (Bin (..), BinP (..))
import Data.Nat (Nat (..))
import Data.Proxy (Proxy (..))
import Data.Type.Equality ((:~:) (..), TestEquality (..))
import Data.Typeable (Typeable)
import Numeric.Natural (Natural)
import Data.Type.BinP (SBinP (..), SBinPI (..))
import qualified Data.Type.Nat as N
import qualified GHC.TypeLits as GHC
import qualified Data.Type.BinP as BP
data SBin (b :: Bin) where
SBZ :: SBin 'BZ
SBP :: SBinPI b => SBin ('BP b)
deriving (Typeable)
class SBinI (b :: Bin) where sbin :: SBin b
instance SBinI 'BZ where sbin = SBZ
instance SBinPI b => SBinI ('BP b ) where sbin = SBP
withSBin :: SBin b -> (SBinI b => r) -> r
withSBin SBZ k = k
withSBin SBP k = k
reify :: forall r. Bin -> (forall b. SBinI b => Proxy b -> r) -> r
reify BZ k = k (Proxy :: Proxy 'BZ)
reify (BP b) k = BP.reify b (\(_ :: Proxy b) -> k (Proxy :: Proxy ('BP b)))
reflect :: forall b proxy. SBinI b => proxy b -> Bin
reflect p = case sbin :: SBin b of
SBZ -> BZ
SBP -> BP (aux p)
where
aux :: forall bn. SBinPI bn => proxy ('BP bn) -> BinP
aux _ = BP.reflect (Proxy :: Proxy bn)
reflectToNum :: forall b proxy a. (SBinI b, Num a) => proxy b -> a
reflectToNum p = case sbin :: SBin b of
SBZ -> 0
SBP -> aux p
where
aux :: forall bn. SBinPI bn => proxy ('BP bn) -> a
aux _ = BP.reflectToNum (Proxy :: Proxy bn)
sbinToBin :: forall n. SBin n -> Bin
sbinToBin SBZ = BZ
sbinToBin s@SBP = aux s where
aux :: forall m. SBinPI m => SBin ('BP m) -> Bin
aux _ = BP (BP.sbinpToBinP (sbinp :: SBinP m))
sbinToNatural :: forall n. SBin n -> Natural
sbinToNatural SBZ = 0
sbinToNatural s@SBP = aux s where
aux :: forall m. SBinPI m => SBin ('BP m) -> Natural
aux _ = BP.sbinpToNatural (sbinp :: SBinP m)
eqBin :: forall a b. (SBinI a, SBinI b) => Maybe (a :~: b)
eqBin = case (sbin :: SBin a, sbin :: SBin b) of
(SBZ, SBZ) -> Just Refl
(SBP, SBP) -> recur where
recur :: forall n m. (SBinPI n, SBinPI m) => Maybe ('BP n :~: 'BP m)
recur = do
Refl <- BP.eqBinP :: Maybe (n :~: m)
return Refl
_ -> Nothing
instance TestEquality SBin where
testEquality SBZ SBZ = Just Refl
testEquality SBP SBP = recur where
recur :: forall n m. (SBinPI n, SBinPI m) => Maybe ('BP n :~: 'BP m)
recur = do
Refl <- BP.eqBinP :: Maybe (n :~: m)
return Refl
testEquality _ _ = Nothing
induction
:: forall b f. SBinI b
=> f 'BZ
-> f ('BP 'BE)
-> (forall bb. SBinPI bb => f ('BP bb) -> f ('BP ('B0 bb)))
-> (forall bb. SBinPI bb => f ('BP bb) -> f ('BP ('B1 bb)))
-> f b
induction z e o i = case sbin :: SBin b of
SBZ -> z
SBP -> go
where
go :: forall bb. SBinPI bb => f ('BP bb)
go = case sbinp :: SBinP bb of
SBE -> e
SB0 -> o go
SB1 -> i go
type family ToGHC (b :: Bin) :: GHC.Nat where
ToGHC 'BZ = 0
ToGHC ('BP n) = BP.ToGHC n
type family FromGHC (n :: GHC.Nat) :: Bin where
FromGHC n = FromGHC' (GhcDivMod2 n)
type family FromGHC' (p :: (GHC.Nat, Bool)) :: Bin where
FromGHC' '(0, 'False) = 'BZ
FromGHC' '(0, 'True) = 'BP 'BE
FromGHC' '(n, 'False) = Mult2 (FromGHC n)
FromGHC' '(n, 'True) = 'BP (Mult2Plus1 (FromGHC n))
type family GhcDivMod2 (n :: GHC.Nat) :: (GHC.Nat, Bool) where
GhcDivMod2 0 = '(0, 'False)
GhcDivMod2 1 = '(0, 'True)
GhcDivMod2 n = GhcDivMod2' (GhcDivMod2 (n GHC.- 2))
type family GhcDivMod2' (p :: (GHC.Nat, Bool)) :: (GHC.Nat, Bool) where
GhcDivMod2' '(n, b) = '(1 GHC.+ n, b)
type family ToNat (b :: Bin) :: Nat where
ToNat 'BZ = 'Z
ToNat ('BP n) = BP.ToNat n
type family FromNat (n :: Nat) :: Bin where
FromNat n = FromNat' (N.DivMod2 n)
type family FromNat' (p :: (Nat, Bool)) :: Bin where
FromNat' '( 'Z, 'False) = 'BZ
FromNat' '( 'Z, 'True) = 'BP 'BE
FromNat' '( n, 'False) = Mult2 (FromNat n)
FromNat' '( n, 'True) = 'BP (Mult2Plus1 (FromNat n))
type family Mult2 (b :: Bin) :: Bin where
Mult2 'BZ = 'BZ
Mult2 ('BP n) = 'BP ('B0 n)
type family Mult2Plus1 (b :: Bin) :: BinP where
Mult2Plus1 'BZ = 'BE
Mult2Plus1 ('BP n) = ('B1 n)
type Succ b = 'BP (Succ' b)
type family Succ' (b :: Bin) :: BinP where
Succ' 'BZ = 'BE
Succ' ('BP b) = BP.Succ b
type Succ'' b = 'BP (BP.Succ b)
withSucc :: forall b r. SBinI b => Proxy b -> (SBinPI (Succ' b) => r) -> r
withSucc p k = case sbin :: SBin b of
SBZ -> k
SBP -> withSucc' p k
withSucc' :: forall b r. SBinPI b => Proxy ('BP b) -> (SBinPI (BP.Succ b) => r) -> r
withSucc' _ k = BP.withSucc (Proxy :: Proxy b) k
type family Pred (b :: BinP) :: Bin where
Pred 'BE = 'BZ
Pred ('B1 n) = 'BP ('B0 n)
Pred ('B0 n) = 'BP (Pred' n)
type family Pred' (b :: BinP) :: BinP where
Pred' 'BE = 'BE
Pred' ('B1 m) = 'B1 ('B0 m)
Pred' ('B0 m) = 'B1 (Pred' m)
type family Plus (a :: Bin) (b :: Bin) :: Bin where
Plus 'BZ b = b
Plus a 'BZ = a
Plus ('BP a) ('BP b) = 'BP (BP.Plus a b)
type Bin0 = 'BZ
type Bin1 = 'BP BP.BinP1
type Bin2 = 'BP BP.BinP2
type Bin3 = 'BP BP.BinP3
type Bin4 = 'BP BP.BinP4
type Bin5 = 'BP BP.BinP5
type Bin6 = 'BP BP.BinP6
type Bin7 = 'BP BP.BinP7
type Bin8 = 'BP BP.BinP8
type Bin9 = 'BP BP.BinP9