{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Overloaded.Numerals (
FromNumeral (..),
defaultFromNumeral,
) where
import Data.Bin.Pos (Pos (..))
import Data.BinP.PosP (PosP (..))
import Data.Fin (Fin (..))
import Data.Proxy (Proxy (..))
import Data.Word (Word16, Word32, Word64, Word8)
import GHC.Exts (Constraint)
import GHC.TypeLits (ErrorMessage (..), Symbol, TypeError)
import GHC.TypeNats (type (<=?), KnownNat, Nat, natVal)
import Numeric.Natural (Natural)
import qualified Data.Bin as B
import qualified Data.BinP.PosP as PP
import qualified Data.Type.Bin as B
import qualified Data.Type.BinP as BP
import qualified Data.Type.Nat as N
class FromNumeral (n :: Nat) a where
fromNumeral :: a
defaultFromNumeral :: forall n a. (KnownNat n, Integral a) => a
defaultFromNumeral = fromIntegral $ natVal (Proxy :: Proxy n)
instance KnownNat n => FromNumeral n Natural where
fromNumeral = natVal (Proxy :: Proxy n)
instance KnownNat n => FromNumeral n Integer where
fromNumeral = defaultFromNumeral @n
instance KnownNat n => FromNumeral n Int where
fromNumeral = defaultFromNumeral @n
type family OverflowCheck (n :: Nat) (t :: Symbol) (b :: Bool) :: Constraint where
OverflowCheck n t 'True = ()
OverflowCheck n t 'False = TypeError
('Text "Overflowing " ':<>: 'Text t ':<>: 'Text ": " ':<>: 'ShowType n)
instance (KnownNat n, OverflowCheck n "Word8" (n <=? 0xff)) => FromNumeral n Word8 where
fromNumeral = defaultFromNumeral @n
instance (KnownNat n, OverflowCheck n "Word8" (n <=? 0xffff)) => FromNumeral n Word16 where
fromNumeral = defaultFromNumeral @n
instance (KnownNat n, OverflowCheck n "Word8" (n <=? 0xffffffff)) => FromNumeral n Word32 where
fromNumeral = defaultFromNumeral @n
instance (KnownNat n, OverflowCheck n "Word8" (n <=? 0xffffffffffffffff)) => FromNumeral n Word64 where
fromNumeral = defaultFromNumeral @n
instance KnownNat n => FromNumeral n N.Nat where
fromNumeral = defaultFromNumeral @n
type family IsLess (p :: Nat) (q :: Nat) :: Constraint where
IsLess p q = IsLess' (q <=? p) p q
type family IsLess' (b :: Bool) (p :: Nat) (q :: Nat) :: Constraint where
IsLess' 'False p q = ()
IsLess' 'True p q = TypeError ('ShowType p ':<>: 'Text " is not less than " ':<>: 'ShowType q)
class FinFromNumeral (n :: N.Nat) (m :: N.Nat) where
finFromNumeral :: Proxy n -> Fin m
instance FinFromNumeral 'N.Z ('N.S m) where
finFromNumeral _ = FZ
instance FinFromNumeral n m => FinFromNumeral ('N.S n) ('N.S m) where
finFromNumeral _ = FS (finFromNumeral (Proxy :: Proxy n))
instance (FinFromNumeral (N.FromGHC n) m, IsLess n (N.ToGHC m)) => FromNumeral n (Fin m) where
fromNumeral = finFromNumeral (Proxy :: Proxy (N.FromGHC n))
instance KnownNat n => FromNumeral n B.Bin where
fromNumeral = defaultFromNumeral @n
instance (KnownNat n, (1 <=? n) ~ 'True) => FromNumeral n B.BinP where
fromNumeral = defaultFromNumeral @n
class PosFromNumeral (n :: N.Nat) (b :: B.BinP) where
posFromNumeral:: Proxy n -> PosP b
instance B.SBinPI b => PosFromNumeral 'N.Z b where
posFromNumeral _ = PP.top
instance (B.SBinPI bp, PosFromNumeral n bp, B.Pred b ~ 'B.BP bp, BP.Succ bp ~ b) => PosFromNumeral ('N.S n) b where
posFromNumeral _ = PP.pop (posFromNumeral (Proxy :: Proxy n))
instance (PosFromNumeral (N.FromGHC n) b, IsLess n (BP.ToGHC b)) => FromNumeral n (PosP b) where
fromNumeral = posFromNumeral (Proxy :: Proxy (N.FromGHC n))
instance (PosFromNumeral (N.FromGHC n) b, IsLess n (BP.ToGHC b)) => FromNumeral n (Pos ('B.BP b)) where
fromNumeral = Pos (posFromNumeral (Proxy :: Proxy (N.FromGHC n)))