{-# LANGUAGE UndecidableSuperClasses #-} {-# LANGUAGE DefaultSignatures #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE GADTs #-} ----------------------------------------------------------------------------- -- | -- Module : Type.Class.Witness -- Copyright : Copyright (C) 2015 Kyle Carter -- License : BSD3 -- -- Maintainer : Kyle Carter -- Stability : experimental -- Portability : RankNTypes -- -- A type @t@ that is a @'Witness' p q t@ provides a 'Constraint' entailment -- of @q@, given that @p@ holds. -- -- The 'Witness' class uses an associated 'Constraint' @WitnessC@ to -- maintain backwards inference of 'Witness' instances with respect -- to type refinement. See the 'Known' class for more information. -- -- Heavily inspired by ekmett's constraints library: -- -- -- The code provided here does not /quite/ subsume the @constraints@ -- library, as we do not give classes and instances for representing -- the standard library's class heirarchy and instance definitions. ---------------------------------------------------------------------------- module Type.Class.Witness ( module Type.Class.Witness , module Exports ) where import Type.Class.Known import Type.Family.Constraint import Data.Type.Equality as Exports import Data.Void as Exports hiding (absurd) import qualified Data.Void as Void import Prelude hiding (id,(.)) import Control.Category import Control.Arrow import Unsafe.Coerce -- Wit {{{ -- | A reified 'Constraint'. data Wit :: Constraint -> * where Wit :: c => Wit c data Wit1 :: (k -> Constraint) -> k -> * where Wit1 :: c a => Wit1 c a -- }}} -- (:-) {{{ -- | Reified evidence of 'Constraint' entailment. -- -- Given a term of @p :- q@, the Constraint @q@ holds -- if @p@ holds. -- -- Entailment of 'Constraint's form a 'Category': -- -- >>> id :: p :- p -- >>> (.) :: (q :- r) -> (p :-> q) -> (p :- r) data (:-) :: Constraint -> Constraint -> * where Sub :: { getSub :: p => Wit q } -> p :- q infixr 4 :- instance Category (:-) where id = Sub Wit Sub bc . Sub ab = Sub $ bc \\ ab transC :: (b :- c) -> (a :- b) -> a :- c transC = (.) -- }}} -- Witness {{{ -- | A general eliminator for entailment. -- -- Given a term of type @t@ with an instance @Witness p q t@ -- and a term of type @r@ that depends on 'Constraint' @q@, -- we can reduce the Constraint to @p@. -- -- If @p@ is @ØC@, i.e. the empty 'Constraint' @()@, then -- a Witness @t@ can completely discharge the Constraint @q@. class WitnessC p q t => Witness (p :: Constraint) (q :: Constraint) (t :: *) | t -> p q where type WitnessC p q t :: Constraint type WitnessC p q t = ØC (\\) :: p => (q => r) -> t -> r infixl 1 \\ (//) :: (Witness p q t, p) => t -> (q => r) -> r t // r = r \\ t infixr 0 // -- | Convert a 'Witness' to a canonical reified 'Constraint'. witnessed :: Witness ØC q t => t -> Wit q witnessed t = Wit \\ t -- | Convert a 'Witness' to a canonical reified entailment. entailed :: Witness p q t => t -> p :- q entailed t = Sub (Wit \\ t) -- }}} -- Constraint Combinators {{{ class Fails (c :: Constraint) where failC :: c :- Fail absurdC :: Fails a => a :- b absurdC = contraC failC class c => Const (c :: Constraint) (d :: k) where constC :: Wit c instance c => Const c d where constC = Wit class f (g a) => (∘) (f :: l -> Constraint) (g :: k -> l) (a :: k) where compC :: Wit (f (g a)) instance f (g a) => (f ∘ g) a where compC = Wit infixr 9 ∘ class (f a,g a) => (∧) (f :: k -> Constraint) (g :: k -> Constraint) (a :: k) where conjC :: (Wit (f a),Wit (g a)) infixr 7 ∧ instance (f a,g a) => (f ∧ g) a where conjC = (Wit,Wit) class (∨) (f :: k -> Constraint) (g :: k -> Constraint) (a :: k) where disjC :: Either (Wit (f a)) (Wit (g a)) infixr 6 ∨ eitherC :: forall f g a b. f a :- b -> g a :- b -> (f ∨ g) a :- b eitherC f g = Sub $ case (disjC :: Either (Wit (f a)) (Wit (g a)),f,g) of (Left a,Sub b,_ ) -> b \\ a (Right a,_ ,Sub b) -> b \\ a pureC :: b => a :- b pureC = Sub Wit contraC :: a :- Fail -> a :- b contraC = (bottom .) -- }}} -- Forall {{{ class Forall (p :: k -> Constraint) (q :: k -> Constraint) where forall :: p a :- q a default forall :: q a => p a :- q a forall = pureC -- }}} -- Initial/Terminal {{{ toEquality :: (a ~ b) :- (c ~ d) -> a :~: b -> c :~: d toEquality p Refl = Refl \\ p commute :: (a ~ b) :- (b ~ a) commute = Sub Wit type family Holds (b :: Bool) (c :: Constraint) :: Constraint where Holds True c = c Holds False c = ØC falso :: (b ~ False) :- Holds b c falso = Sub Wit top :: a :- ØC top = Sub Wit bottom :: Fail :- c bottom = falso instance Witness ØC c (Wit c) where r \\ Wit = r instance Witness ØC (c a) (Wit1 c a) where r \\ Wit1 = r -- | An entailment @p :- q@ is a Witness of @q@, given @p@. instance Witness p q (p :- q) where r \\ Sub Wit = r -- | A type equality @a ':~:' b@ is a Witness that @(a ~ b)@. instance Witness ØC (a ~ b) (a :~: b) where r \\ Refl = r -- | If the constraint @c@ holds, there is a canonical construction -- for a term of type @'Wit' c@, viz. the constructor @Wit@. instance c => Known Wit c where type KnownC Wit c = c known = Wit instance c a => Known (Wit1 c) a where type KnownC (Wit1 c) a = c a known = Wit1 -- | Constraint chaining under @Maybe@. (//?) :: (Witness p q t, p) => Maybe t -> (q => Maybe r) -> Maybe r (//?) = \case Just t -> (\\ t) _ -> \_ -> Nothing infixr 0 //? (//?+) :: (Witness p q t, p) => Either e t -> (q => Either e r) -> Either e r (//?+) = \case Left e -> \_ -> Left e Right t -> (\\ t) infixr 0 //?+ witMaybe :: (Witness p q t, p) => Maybe t -> (q => Maybe r) -> Maybe r -> Maybe r witMaybe mt y n = case mt of Just t -> y \\ t _ -> n qed :: Maybe (a :~: a) qed = Just Refl impossible :: a -> Void impossible = unsafeCoerce exFalso :: Wit Fail -> a exFalso p = castWith q () where q :: () :~: a q = toEquality (contraC r) Refl r :: (b ~ b) :- Fail r = Sub p (=?=) :: TestEquality f => f a -> f b -> Maybe (a :~: b) (=?=) = testEquality infix 4 =?= class TestEquality1 (f :: k -> l -> *) where testEquality1 :: f a c -> f b c -> Maybe (a :~: b) (=??=) :: TestEquality1 f => f a c -> f b c -> Maybe (a :~: b) (=??=) = testEquality1 infix 4 =??= -- }}} -- Dec {{{ data Dec a = Proven a | Refuted (a -> Void) class DecEquality (f :: k -> *) where decideEquality :: f a -> f b -> Dec (a :~: b) decCase :: Dec a -> (a -> r) -> ((a -> Void) -> r) -> r decCase d y n = case d of Proven a -> y a Refuted b -> n b -- }}} absurd :: Arrow p => p Void a absurd = arr Void.absurd {- -- Category Classes {{{ class Category c => Monoidal (c :: k -> k -> *) where type Tensor c :: k -> k -> k type Unit c :: k (.*.) :: c v w -> c x y -> c (Tensor c v x) (Tensor c w y) assoc :: c (Tensor c (Tensor c x y) z) (Tensor c x (Tensor c y z)) unitL :: c (Tensor c (Unit c) x) x unitR :: c (Tensor c x (Unit c)) x infixr 3 .*. class Category c => Symmetric (c :: k -> k -> *) where symm :: c a b -> c b a instance Category p => Symmetric (Bij p) where symm p = bwd p <-> fwd p instance Monoidal (->) where type Tensor (->) = (,) type Unit (->) = () (f .*. g) (a,b) = (f a,g b) assoc ((x,y),z) = (x,(y,z)) unitL (_,x) = x unitR (x,_) = x instance (Symmetric p, Monoidal p) => Monoidal (Bij p) where type Tensor (Bij p) = Tensor p type Unit (Bij p) = Unit p (.*.) = (***) assoc = assoc <-> symm assoc unitL = unitL <-> symm unitL unitR = unitR <-> symm unitR (***) :: Monoidal p => Bij p a b -> Bij p c d -> Bij p (Tensor p a c) (Tensor p b d) f *** g = (fwd f .*. fwd g) <-> (bwd f .*. bwd g) infixr 3 *** -- }}} -}