{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Type.Data.Num.Unary (
Unary, unary, Un, Zero, Succ, zero, succ,
Singleton(..), singleton, singletonFromProxy,
integerFromSingleton, integralFromSingleton,
integralFromProxy,
Natural(..), Positive(..),
(:+:), (:*:),
reifyNatural,
) where
import qualified Type.Data.Num as Num
import qualified Type.Base.Proxy as Proxy
import Type.Base.Proxy (Proxy(Proxy))
import Text.Printf (printf)
import Prelude hiding (succ)
data Unary
data Un x
data Zero
data Succ x
zero :: Proxy Zero
zero = Proxy
succ :: Proxy n -> Proxy (Succ n)
succ Proxy = Proxy
class Natural n where
switchNat ::
f Zero ->
(forall m. (Natural m) => f (Succ m)) ->
f n
instance Natural Zero where switchNat x _ = x
instance Natural n => Natural (Succ n) where switchNat _ x = x
class (Natural n) => Positive n where
switchPos ::
(forall m. (Natural m) => f (Succ m)) ->
f n
instance Natural n => Positive (Succ n) where switchPos x = x
type family x :+: y
type instance x :+: Zero = x
type instance x :+: Succ y = Succ (x :+: y)
type family x :*: y
type instance _x :*: Zero = Zero
type instance x :*: Succ y = x :+: (x :*: y)
newtype Singleton n = Singleton Integer
instance (Natural n) => Num.Integer (Un n) where
singleton = singletonToGeneric singleton
type Repr (Un n) = Unary
singletonToGeneric :: Singleton n -> Num.Singleton (Un n)
singletonToGeneric (Singleton n) = Num.Singleton n
singleton :: (Natural n) => Singleton n
singleton =
switchNat
(Singleton 0)
(succSingleton singleton)
succSingleton ::
(Natural n) =>
Singleton n -> Singleton (Succ n)
succSingleton (Singleton n) = Singleton $ n+1
integerFromSingleton :: (Natural n) => Singleton n -> Integer
integerFromSingleton (Singleton n) = n
integralFromSingleton :: (Natural n, Num a) => Singleton n -> a
integralFromSingleton = fromInteger . integerFromSingleton
singletonFromProxy :: (Natural n) => Proxy n -> Singleton n
singletonFromProxy Proxy = singleton
integralFromProxy :: (Natural n, Num a) => Proxy n -> a
integralFromProxy = integralFromSingleton . singletonFromProxy
instance Num.Representation Unary where
reifyIntegral _ i k = reifyIntegral i (k . unary)
unary :: Proxy n -> Proxy (Un n)
unary Proxy = Proxy
stripUn :: Proxy (Un n) -> Proxy n
stripUn Proxy = Proxy
reifyIntegral :: Integer -> (forall s. Natural s => Proxy s -> w) -> w
reifyIntegral n f =
if n < 0
then error "negative unary numbers not supported so far"
else reifyNatural n f
reifyNatural :: Integer -> (forall s. Natural s => Proxy s -> w) -> w
reifyNatural n f =
if n>0
then reifyNatural (n-1) (f . succ)
else f zero
type instance Un x Num.:+: Un y = Un (x :+: y)
type instance Un x Num.:*: Un y = Un (x :*: y)
instance Natural a => Proxy.Show (Un a) where
showsPrec prec =
(\n -> showParen (prec>10) (showString (printf "unary u%d" n)))
. integerFromSingleton . singletonFromProxy . stripUn