combinat-compat-0.2.8.2: Math/Combinat/TypeLevel.hs
-- | Type-level hackery.
--
-- This module is used for groups whose parameters are encoded as type-level natural numbers,
-- for example finite cyclic groups, free groups, symmetric groups and braid groups.
--
{-# LANGUAGE PolyKinds, DataKinds, KindSignatures, ScopedTypeVariables,
ExistentialQuantification, Rank2Types #-}
module Math.Combinat.TypeLevel
( -- * Proxy
Proxy(..)
, proxyUndef
, proxyOf
, proxyOf1
, proxyOf2
, asProxyTypeOf -- defined in Data.Proxy
, asProxyTypeOf1
-- * Type-level naturals as type arguments
, typeArg
, iTypeArg
-- * Hiding the type parameter
, Some (..)
, withSome , withSomeM
, selectSome , selectSomeM
, withSelected , withSelectedM
)
where
--------------------------------------------------------------------------------
import Data.Proxy ( Proxy(..) , asProxyTypeOf )
import GHC.TypeLits
import Math.Combinat.Numbers.Primes ( isProbablyPrime )
--------------------------------------------------------------------------------
-- * Proxy
proxyUndef :: Proxy a -> a
proxyUndef _ = error "proxyUndef"
proxyOf :: a -> Proxy a
proxyOf _ = Proxy
proxyOf1 :: f a -> Proxy a
proxyOf1 _ = Proxy
proxyOf2 :: g (f a) -> Proxy a
proxyOf2 _ = Proxy
asProxyTypeOf1 :: f a -> Proxy a -> f a
asProxyTypeOf1 y _ = y
--------------------------------------------------------------------------------
-- * Type-level naturals as type arguments
typeArg :: KnownNat n => f (n :: Nat) -> Integer
typeArg = natVal . proxyOf1
iTypeArg :: KnownNat n => f (n :: Nat) -> Int
iTypeArg = fromIntegral . typeArg
--------------------------------------------------------------------------------
-- * Hiding the type parameter
-- | Hide the type parameter of a functor. Example: @Some Braid@
data Some f = forall n. KnownNat n => Some (f n)
-- | Uses the value inside a 'Some'
withSome :: Some f -> (forall n. KnownNat n => f n -> a) -> a
withSome some polyFun = case some of { Some stuff -> polyFun stuff }
-- | Monadic version of 'withSome'
withSomeM :: Monad m => Some f -> (forall n. KnownNat n => f n -> m a) -> m a
withSomeM some polyAct = case some of { Some stuff -> polyAct stuff }
-- | Given a polymorphic value, we select at run time the
-- one specified by the second argument
selectSome :: Integral int => (forall n. KnownNat n => f n) -> int -> Some f
selectSome poly n = case someNatVal (fromIntegral n :: Integer) of
Nothing -> error "selectSome: not a natural number"
Just snat -> case snat of
SomeNat pxy -> Some (asProxyTypeOf1 poly pxy)
-- | Monadic version of 'selectSome'
selectSomeM :: forall m f int. (Integral int, Monad m) => (forall n. KnownNat n => m (f n)) -> int -> m (Some f)
selectSomeM runPoly n = case someNatVal (fromIntegral n :: Integer) of
Nothing -> error "selectSomeM: not a natural number"
Just snat -> case snat of
SomeNat pxy -> do
poly <- runPoly
return $ Some (asProxyTypeOf1 poly pxy)
-- | Combination of 'selectSome' and 'withSome': we make a temporary structure
-- of the given size, but we immediately consume it.
withSelected
:: Integral int
=> (forall n. KnownNat n => f n -> a)
-> (forall n. KnownNat n => f n)
-> int
-> a
withSelected f x n = withSome (selectSome x n) f
-- | (Half-)monadic version of 'withSelected'
withSelectedM
:: forall m f int a. (Integral int, Monad m)
=> (forall n. KnownNat n => f n -> a)
-> (forall n. KnownNat n => m (f n))
-> int
-> m a
withSelectedM f mx n = do
s <- selectSomeM mx n
return (withSome s f)
--------------------------------------------------------------------------------