parameterized-utils-2.1.3.0: src/Data/Parameterized/WithRepr.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-|
Copyright : (c) Galois, Inc 2019
This module declares a class with a single method that can be used to
derive a 'KnownRepr' constraint from an explicit 'Repr' argument.
Clients of this method need only create an empty instance. The default
implementation suffices.
For example, suppose we have defined a 'Repr' type for 'Peano' numbers:
@
data Peano = Z | S Peano
data PeanoRepr p where
ZRepr :: PeanoRepr Z
SRepr :: PeanoRepr p -> PeanoRepr (S p)
-- KnownRepr instances
@
Then the instance for this class
@
instance IsRepr PeanoRepr
@
means that functions with 'KnownRepr' constraints can be used after
pattern matching.
@
f :: KnownRepr PeanoRepr a => ...
example :: PeanoRepr n -> ...
example ZRepr = ...
example (SRepr (pm::PeanoRepr m)) = ... withRepr pm f ...
@
NOTE: The type 'f' must be a *singleton* type--- i.e. for a given
type 'a' there should be only one value that inhabits 'f a'. If that
is not the case, this operation can be used to subvert coherence.
Credit: the unsafe implementation of 'withRepr' is taken from the
'withSingI' function in the singletons library
<http://hackage.haskell.org/package/singletons-2.5.1/>. Packaging
this method in a class here makes it more flexible---we do not have to
define a dedicated 'Sing' type, but can use any convenient singleton
as a 'Repr'.
NOTE: if this module is compiled without UNSAFE_OPS, the default
method will not be available.
-}
module Data.Parameterized.WithRepr(IsRepr(..)) where
import Data.Kind
import Data.Parameterized.Classes
#ifdef UNSAFE_OPS
import Data.Constraint(Dict(..))
import Unsafe.Coerce(unsafeCoerce)
import Data.Parameterized.NatRepr (NatRepr)
import Data.Parameterized.SymbolRepr (SymbolRepr)
import Data.Parameterized.Peano (PeanoRepr)
import Data.Parameterized.Context(Assignment)
import Data.Parameterized.List(List)
#else
import Data.Parameterized.Peano (PeanoRepr,PeanoView(..))
#endif
import Data.Parameterized.BoolRepr
-- | Turn an explicit Repr value into an implict KnownRepr constraint
class IsRepr (f :: k -> Type) where
withRepr :: f a -> (KnownRepr f a => r) -> r
#ifdef UNSAFE_OPS
withRepr si r = case reprInstance si of
Dict -> r
reprInstance :: forall f a . IsRepr f => f a -> Dict (KnownRepr f a)
reprInstance s = with_repr Dict
where
with_repr :: (KnownRepr f a => Dict (KnownRepr f a)) -> Dict (KnownRepr f a)
with_repr si = unsafeCoerce (Don'tInstantiate si) s
newtype DI f a = Don'tInstantiate (KnownRepr f a => Dict (KnownRepr f a))
#endif
------------------------------------
-- Instances for types defined in parameterized-utils
#ifdef UNSAFE_OPS
instance IsRepr NatRepr
instance IsRepr SymbolRepr
instance IsRepr PeanoRepr
instance IsRepr BoolRepr
instance IsRepr f => IsRepr (List f)
instance IsRepr f => IsRepr (Assignment f)
#else
-- awful, slow implementation for PeanoRepr
instance IsRepr PeanoRepr where
withRepr ZRepr f = f
withRepr (SRepr m) f = withRepr m f
instance IsRepr BoolRepr where
withRepr TrueRepr f = f
withRepr FalseRepr f = f
#endif