{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Data.Type.BinP (
SBinP (..),
sbinpToBinP,
sbinpToNatural,
SBinPI (..),
withSBinP,
reify,
reflect,
reflectToNum,
eqBinP,
induction,
Succ,
withSucc,
Plus,
ToGHC, FromGHC,
ToNat,
BinP1, BinP2, BinP3, BinP4, BinP5, BinP6, BinP7, BinP8, BinP9,
) where
import Data.BinP (BinP (..))
import Data.Coerce (coerce)
import Data.Nat (Nat (..))
import Data.Proxy (Proxy (..))
import Data.Type.Equality ((:~:) (..), TestEquality (..))
import Data.Typeable (Typeable)
import Numeric.Natural (Natural)
import qualified Data.Type.Nat as N
import qualified GHC.TypeLits as GHC
data SBinP (b :: BinP) where
SBE :: SBinP 'BE
SB0 :: SBinPI b => SBinP ('B0 b)
SB1 :: SBinPI b => SBinP ('B1 b)
deriving (Typeable)
class SBinPI (b :: BinP) where sbinp :: SBinP b
instance SBinPI 'BE where sbinp = SBE
instance SBinPI b => SBinPI ('B0 b) where sbinp = SB0
instance SBinPI b => SBinPI ('B1 b) where sbinp = SB1
withSBinP :: SBinP b -> (SBinPI b => r) -> r
withSBinP SBE k = k
withSBinP SB0 k = k
withSBinP SB1 k = k
reify :: forall r. BinP -> (forall b. SBinPI b => Proxy b -> r) -> r
reify BE k = k (Proxy :: Proxy 'BE)
reify (B0 b) k = reify b (\(_ :: Proxy b) -> k (Proxy :: Proxy ('B0 b)))
reify (B1 b) k = reify b (\(_ :: Proxy b) -> k (Proxy :: Proxy ('B1 b)))
reflect :: forall b proxy. SBinPI b => proxy b -> BinP
reflect _ = unKP (induction (KP BE) (mapKP B0) (mapKP B1) :: KP BinP b)
reflectToNum :: forall b proxy a. (SBinPI b, Num a) => proxy b -> a
reflectToNum _ = unKP (induction (KP 1) (mapKP (2*)) (mapKP (\x -> 2 * x + 1)) :: KP a b)
sbinpToBinP :: forall n. SBinP n -> BinP
sbinpToBinP s = withSBinP s $ reflect (Proxy :: Proxy n)
sbinpToNatural :: forall n. SBinP n -> Natural
sbinpToNatural s = withSBinP s $ unKP (induction
(KP 1)
(mapKP (2 *))
(mapKP (\x -> succ (2 * x))) :: KP Natural n)
eqBinP :: forall a b. (SBinPI a, SBinPI b) => Maybe (a :~: b)
eqBinP = case (sbinp :: SBinP a, sbinp :: SBinP b) of
(SBE, SBE) -> Just Refl
(SB0, SB0) -> recur where
recur :: forall n m. (SBinPI n, SBinPI m) => Maybe ('B0 n :~: 'B0 m)
recur = do
Refl <- eqBinP :: Maybe (n :~: m)
return Refl
(SB1, SB1) -> recur where
recur :: forall n m. (SBinPI n, SBinPI m) => Maybe ('B1 n :~: 'B1 m)
recur = do
Refl <- eqBinP :: Maybe (n :~: m)
return Refl
_ -> Nothing
instance TestEquality SBinP where
testEquality SBE SBE = Just Refl
testEquality SB0 SB0 = eqBinP
testEquality SB1 SB1 = eqBinP
testEquality _ _ = Nothing
type family ToGHC (b :: BinP) :: GHC.Nat where
ToGHC 'BE = 1
ToGHC ('B0 b) = 2 GHC.* (ToGHC b)
ToGHC ('B1 b) = 1 GHC.+ 2 GHC.* (ToGHC b)
type family FromGHC (n :: GHC.Nat) :: BinP where
FromGHC n = FromGHC' (FromGHCMaybe n)
type family FromGHC' (b :: Maybe BinP) :: BinP where
FromGHC' ('Just b) = b
type family FromGHCMaybe (n :: GHC.Nat) :: Maybe BinP where
FromGHCMaybe n = FromGHCMaybe' (GhcDivMod2 n)
type family FromGHCMaybe' (p :: (GHC.Nat, Bool)) :: Maybe BinP where
FromGHCMaybe' '(0, 'False) = 'Nothing
FromGHCMaybe' '(0, 'True) = 'Just 'BE
FromGHCMaybe' '(n, 'False) = Mult2 (FromGHCMaybe n)
FromGHCMaybe' '(n, 'True) = 'Just (Mult2Plus1 (FromGHCMaybe 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 Mult2 (b :: Maybe BinP) :: Maybe BinP where
Mult2 'Nothing = 'Nothing
Mult2 ('Just n) = 'Just ('B0 n)
type family Mult2Plus1 (b :: Maybe BinP) :: BinP where
Mult2Plus1 'Nothing = 'BE
Mult2Plus1 ('Just n) = ('B1 n)
type family ToNat (b :: BinP) :: Nat where
ToNat 'BE = 'S 'Z
ToNat ('B0 b) = N.Mult2 (ToNat b)
ToNat ('B1 b) = 'S (N.Mult2 (ToNat b))
type family Succ (b :: BinP) :: BinP where
Succ 'BE = 'B0 'BE
Succ ('B0 n) = 'B1 n
Succ ('B1 n) = 'B0 (Succ n)
withSucc :: forall b r. SBinPI b => Proxy b -> (SBinPI (Succ b) => r) -> r
withSucc p k = case sbinp :: SBinP b of
SBE -> k
SB0 -> k
SB1 -> recur p k
where
recur :: forall m s. SBinPI m => Proxy ('B1 m) -> (SBinPI ('B0 (Succ m)) => s) -> s
recur _ k' = withSucc (Proxy :: Proxy m) k'
type family Plus (a :: BinP) (b :: BinP) :: BinP where
Plus 'BE b = Succ b
Plus a 'BE = Succ a
Plus ('B0 a) ('B0 b) = 'B0 (Plus a b)
Plus ('B1 a) ('B0 b) = 'B1 (Plus a b)
Plus ('B0 a) ('B1 b) = 'B1 (Plus a b)
Plus ('B1 a) ('B1 b) = 'B0 (Succ (Plus a b))
induction
:: forall b f. SBinPI b
=> f 'BE
-> (forall bb. SBinPI bb => f bb -> f ('B0 bb))
-> (forall bb. SBinPI bb => f bb -> f ('B1 bb))
-> f b
induction e o i = go where
go :: forall bb. SBinPI bb => f bb
go = case sbinp :: SBinP bb of
SBE -> e
SB0 -> o go
SB1 -> i go
type BinP1 = 'BE
type BinP2 = 'B0 BinP1
type BinP3 = 'B1 BinP1
type BinP4 = 'B0 BinP2
type BinP5 = 'B1 BinP2
type BinP6 = 'B0 BinP3
type BinP7 = 'B1 BinP3
type BinP8 = 'B0 BinP4
type BinP9 = 'B1 BinP4
newtype KP a (b :: BinP) = KP a
unKP :: KP a b -> a
unKP = coerce
mapKP :: (a -> b) -> KP a bn -> KP b bn'
mapKP = coerce