{-# LANGUAGE CPP #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE MagicHash #-} {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ViewPatterns #-} ----------------------------------------------------------------------------- -- | -- Module : Data.Constraint.Bare -- Copyright : (c) 2019 Artem Chirkin -- License : BSD3 -- Portability : non-portable -- -- Extract a Constraint from a Dict to manipulate it as a plain value. -- It is supposed to be used in compiler plugins -- -- to move around instances of type classes. -- ----------------------------------------------------------------------------- module Data.Constraint.Bare ( BareConstraint, pattern DictValue , dictToBare, bareToDict , withBareConstraint ) where import Data.Constraint (Dict (..)) import GHC.Base (Constraint, Type, unsafeCoerce#) -- | An unsafeCoerced pointer to a Constraint, such as a class function dictionary. data BareConstraint :: Constraint -> Type -- | Extract the constraint inside the Dict GADT as if it was -- an ordinary value of kind `Type`. -- -- It exploits the feature of the GHC core language -- -- representing constraints as ordinary type arguments of a function. -- Thus, I unsafeCoerce between a function with one argument and a function -- with no arguments and one constraint. -- -- This pattern has never been tested with multiple constraints. pattern DictValue :: BareConstraint c -> Dict c pattern DictValue c <- (dictToBare -> c) where DictValue c = bareToDict c #if __GLASGOW_HASKELL__ >= 802 {-# COMPLETE DictValue #-} #endif -- | Extract a `Constraint` from a `Dict` dictToBare :: forall c . Dict c -> BareConstraint c dictToBare Dict = case (unsafeCoerce# id :: Magic c (BareConstraint c)) of Magic c -> c {-# INLINE dictToBare #-} -- | Wrap a `Constraint` into a `Dict` bareToDict :: forall c . BareConstraint c -> Dict c bareToDict = unsafeCoerce# (Magic Dict :: Magic c (Dict c)) {-# INLINE bareToDict #-} -- | Provide a constraint to a function using `BareConstraint`. -- This allows to provide constraints on-demand (lazily), rather than eagerly -- pattern-matching against `Dict` before executing the function. withBareConstraint :: forall c r . BareConstraint c -> (c => r) -> r withBareConstraint bc f = unsafeCoerce# (Magic f :: Magic c r) bc newtype Magic c r = Magic (c => r)