{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
module Data.Constraint.Deferrable
( UnsatisfiedConstraint(..)
, Deferrable(..)
, defer
, deferred
, (:~~:)(HRefl)
, (:~:)(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))
import GHC.Types (type (~~))
import Data.Type.Equality.Hetero ((:~~:)(HRefl))
newtype UnsatisfiedConstraint = UnsatisfiedConstraint String
deriving (Typeable, Int -> UnsatisfiedConstraint -> ShowS
[UnsatisfiedConstraint] -> ShowS
UnsatisfiedConstraint -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [UnsatisfiedConstraint] -> ShowS
$cshowList :: [UnsatisfiedConstraint] -> ShowS
show :: UnsatisfiedConstraint -> String
$cshow :: UnsatisfiedConstraint -> String
showsPrec :: Int -> UnsatisfiedConstraint -> ShowS
$cshowsPrec :: Int -> UnsatisfiedConstraint -> ShowS
Show)
instance Exception UnsatisfiedConstraint
class Deferrable p where
deferEither :: (p => r) -> Either String r
deferred :: forall p. Deferrable p :- p
deferred :: forall (p :: Constraint). Deferrable p :- p
deferred = forall (a :: Constraint) (b :: Constraint). (a => Dict b) -> a :- b
Sub forall a b. (a -> b) -> a -> b
$ forall (p :: Constraint) r. Deferrable p => (p => r) -> r
defer @p forall (a :: Constraint). a => Dict a
Dict
defer :: forall p r. Deferrable p => (p => r) -> r
defer :: forall (p :: Constraint) r. Deferrable p => (p => r) -> r
defer p => r
r = forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (forall a e. Exception e => e -> a
throw forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> UnsatisfiedConstraint
UnsatisfiedConstraint) forall a. a -> a
id forall a b. (a -> b) -> a -> b
$ forall (p :: Constraint) r.
Deferrable p =>
(p => r) -> Either String r
deferEither @p p => r
r
showTypeRep :: forall t. Typeable t => String
showTypeRep :: forall {k} (t :: k). Typeable t => String
showTypeRep = forall a. Show a => a -> String
show forall a b. (a -> b) -> a -> b
$ forall {k} (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (forall {k} (t :: k). Proxy t
Proxy @t)
instance Deferrable () where
deferEither :: forall r. ((() :: Constraint) => r) -> Either String r
deferEither (() :: Constraint) => r
r = forall a b. b -> Either a b
Right (() :: Constraint) => r
r
instance (Typeable k, Typeable (a :: k), Typeable b) => Deferrable (a ~ b) where
deferEither :: forall r. ((a ~ b) => r) -> Either String r
deferEither (a ~ b) => r
r = case forall a b. (Typeable a, Typeable b) => a -> Maybe b
cast (forall {k} (a :: k). a :~: a
Refl :: a :~: a) :: Maybe (a :~: b) of
Just a :~: b
Refl -> forall a b. b -> Either a b
Right (a ~ b) => r
r
Maybe (a :~: b)
Nothing -> forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$
String
"deferred type equality: type mismatch between `" forall a. [a] -> [a] -> [a]
++ forall {k} (t :: k). Typeable t => String
showTypeRep @a forall a. [a] -> [a] -> [a]
++ String
"’ and `" forall a. [a] -> [a] -> [a]
++ forall {k} (t :: k). Typeable t => String
showTypeRep @b forall a. [a] -> [a] -> [a]
++ String
"'"
instance (Typeable i, Typeable j, Typeable (a :: i), Typeable (b :: j)) => Deferrable (a ~~ b) where
deferEither :: forall r. ((a ~~ b) => r) -> Either String r
deferEither (a ~~ b) => r
r = case forall a b. (Typeable a, Typeable b) => a -> Maybe b
cast (forall {k1} (a :: k1). a :~~: a
HRefl :: a :~~: a) :: Maybe (a :~~: b) of
Just a :~~: b
HRefl -> forall a b. b -> Either a b
Right (a ~~ b) => r
r
Maybe (a :~~: b)
Nothing -> forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$
String
"deferred type equality: type mismatch between `" forall a. [a] -> [a] -> [a]
++ forall {k} (t :: k). Typeable t => String
showTypeRep @a forall a. [a] -> [a] -> [a]
++ String
"’ and `" forall a. [a] -> [a] -> [a]
++ forall {k} (t :: k). Typeable t => String
showTypeRep @b forall a. [a] -> [a] -> [a]
++ String
"'"
instance (Deferrable a, Deferrable b) => Deferrable (a, b) where
deferEither :: forall r. ((a, b) => r) -> Either String r
deferEither (a, b) => r
r = forall (m :: * -> *) a. Monad m => m (m a) -> m a
join forall a b. (a -> b) -> a -> b
$ forall (p :: Constraint) r.
Deferrable p =>
(p => r) -> Either String r
deferEither @a forall a b. (a -> b) -> a -> b
$ forall (p :: Constraint) r.
Deferrable p =>
(p => r) -> Either String r
deferEither @b (a, b) => r
r
instance (Deferrable a, Deferrable b, Deferrable c) => Deferrable (a, b, c) where
deferEither :: forall r. ((a, b, c) => r) -> Either String r
deferEither (a, b, c) => r
r = forall (m :: * -> *) a. Monad m => m (m a) -> m a
join forall a b. (a -> b) -> a -> b
$ forall (p :: Constraint) r.
Deferrable p =>
(p => r) -> Either String r
deferEither @a forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. Monad m => m (m a) -> m a
join forall a b. (a -> b) -> a -> b
$ forall (p :: Constraint) r.
Deferrable p =>
(p => r) -> Either String r
deferEither @b forall a b. (a -> b) -> a -> b
$ forall (p :: Constraint) r.
Deferrable p =>
(p => r) -> Either String r
deferEither @c (a, b, c) => r
r