{-# LANGUAGE CPP #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE PolyKinds #-}
#if __GLASGOW_HASKELL__ >= 800
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE TypeInType #-}
#endif
module Data.Constraint.Deferrable
( UnsatisfiedConstraint(..)
, Deferrable(..)
, defer
, deferred
#if __GLASGOW_HASKELL__ >= 800
, defer_
, deferEither_
, (:~~:)(HRefl)
#endif
, (:~:)(Refl)
) where
import Control.Exception
import Control.Monad
import Data.Constraint
import Data.Proxy
import Data.Typeable (Typeable, cast, typeRep)
import Data.Type.Equality ((:~:)(Refl))
#if __GLASGOW_HASKELL__ >= 800
import GHC.Types (type (~~))
#endif
#if __GLASGOW_HASKELL__ >= 801
import Data.Type.Equality ((:~~:)(HRefl))
#endif
data UnsatisfiedConstraint = UnsatisfiedConstraint String
deriving (Typeable, Show)
instance Exception UnsatisfiedConstraint
class Deferrable p where
deferEither :: proxy p -> (p => r) -> Either String r
defer :: forall p r proxy. Deferrable p => proxy p -> (p => r) -> r
defer _ r = either (throw . UnsatisfiedConstraint) id $ deferEither (Proxy :: Proxy p) r
deferred :: forall p. Deferrable p :- p
deferred = Sub $ defer (Proxy :: Proxy p) Dict
#if __GLASGOW_HASKELL__ >= 800
defer_ :: forall p r. Deferrable p => (p => r) -> r
defer_ r = defer @p Proxy r
deferEither_ :: forall p r. Deferrable p => (p => r) -> Either String r
deferEither_ r = deferEither @p Proxy r
#endif
#if __GLASGOW_HASKELL__ >= 800 && __GLASGOW_HASKELL__ < 801
data (a :: i) :~~: (b :: j) where
HRefl :: a :~~: a
deriving Typeable
#endif
showTypeRep :: Typeable t => Proxy t -> String
showTypeRep = show . typeRep
instance Deferrable () where
deferEither _ r = Right r
#if __GLASGOW_HASKELL__ >= 800
instance (Typeable k, Typeable (a :: k), Typeable b) => Deferrable (a ~ b) where
#elif __GLASGOW_HASKELL__ == 710
instance (Typeable a, Typeable b) => Deferrable ((a :: *) ~ (b :: *)) where
#else
instance (Typeable a, Typeable b) => Deferrable (a ~ b) where
#endif
deferEither _ r = case cast (Refl :: a :~: a) :: Maybe (a :~: b) of
Just Refl -> Right r
Nothing -> Left $
"deferred type equality: type mismatch between `" ++ showTypeRep (Proxy :: Proxy a) ++ "’ and `" ++ showTypeRep (Proxy :: Proxy b) ++ "'"
#if __GLASGOW_HASKELL__ >= 800
instance (Typeable i, Typeable j, Typeable (a :: i), Typeable (b :: j)) => Deferrable (a ~~ b) where
deferEither _ r = case cast (HRefl :: a :~~: a) :: Maybe (a :~~: b) of
Just HRefl -> Right r
Nothing -> Left $
"deferred type equality: type mismatch between `" ++ showTypeRep (Proxy :: Proxy a) ++ "’ and `" ++ showTypeRep (Proxy :: Proxy b) ++ "'"
#endif
instance (Deferrable a, Deferrable b) => Deferrable (a, b) where
deferEither _ r = join $ deferEither (Proxy :: Proxy a) $ deferEither (Proxy :: Proxy b) r
instance (Deferrable a, Deferrable b, Deferrable c) => Deferrable (a, b, c) where
deferEither _ r = join $ deferEither (Proxy :: Proxy a) $ join $ deferEither (Proxy :: Proxy b) $ deferEither (Proxy :: Proxy c) r