open-witness 0.3.1 → 0.4
raw patch · 18 files changed
+625/−477 lines, 18 filesdep +constraintsdep +mtldep +open-witnessdep ~basedep ~witness
Dependencies added: constraints, mtl, open-witness, tasty, tasty-hunit
Dependency ranges changed: base, witness
Files
- Data/OpenWitness.hs +0/−134
- Data/OpenWitness/Dynamic.hs +0/−56
- Data/OpenWitness/Exception.hs +0/−48
- Data/OpenWitness/OpenRep.hs +0/−70
- Data/OpenWitness/ST.hs +0/−59
- Data/OpenWitness/Typeable.hs +0/−102
- LICENSE +1/−1
- open-witness.cabal +36/−7
- src/Data/OpenWitness.hs +144/−0
- src/Data/OpenWitness/Dynamic.hs +56/−0
- src/Data/OpenWitness/Exception.hs +49/−0
- src/Data/OpenWitness/Instance.hs +17/−0
- src/Data/OpenWitness/ST.hs +59/−0
- src/Data/OpenWitness/TypeRep.hs +36/−0
- src/Data/OpenWitness/Typeable.hs +120/−0
- src/Data/Type/Heterogeneous.hs +20/−0
- test/Main.hs +63/−0
- test/Object.hs +24/−0
− Data/OpenWitness.hs
@@ -1,134 +0,0 @@-{-# OPTIONS -fno-warn-name-shadowing #-}-module Data.OpenWitness-(- OpenWitness,- RealWorld,IOWitness,newIOWitness,- OW,newOpenWitnessOW,runOW,owToIO,--- unsafeIOWitnessFromInteger,--- unsafeIOWitnessFromString,- iowitness-) where-{- import Prelude;- import Data.List;- import System.Random;- import Language.Haskell.TH;- import Unsafe.Coerce;- import System.IO.Unsafe (unsafePerformIO);- import Control.Concurrent.MVar;- import Control.Monad.Fix;- import Control.Monad.Trans.State;- import Data.Functor.Identity;- import Data.Traversable;- import Data.Hashable;- import Data.Witness;--- unsafeSameType :: a :~: b;- unsafeSameType = unsafeCoerce Refl;-- -- | A witness type that can witness to any type.- -- But values cannot be constructed; they can only be generated in 'IO' and certain other monads.- ;- newtype OpenWitness s (a :: k) = MkOpenWitness Integer deriving Eq;-- instance TestEquality (OpenWitness s) where- {- testEquality (MkOpenWitness ua) (MkOpenWitness ub) =- if ua == ub then Just unsafeSameType else Nothing;- };-- -- | The @s@ type for running 'OW' in 'IO'.- ;- data RealWorld;-- -- | An 'OpenWitness' for 'IO'.- ;- type IOWitness = OpenWitness RealWorld;-- ioWitnessSource :: MVar Integer;- {-# NOINLINE ioWitnessSource #-};- ioWitnessSource = unsafePerformIO (newMVar 0);-- -- | Generate a new 'IOWitness' in 'IO'.- ;- newIOWitness :: forall a. IO (IOWitness a);- newIOWitness = do- {- val <- takeMVar ioWitnessSource;- putMVar ioWitnessSource (val + 1);- return (MkOpenWitness val);- };-- type OWState = Integer;-- -- | A runnable monad in which 'OpenWitness' values can be generated.- -- The @s@ parameter plays the same role as it does in 'ST', preventing 'OpenWitness' values from one run being used in another.- ;- newtype OW s a = MkOW (State OWState a) deriving (Functor,Applicative,Monad,MonadFix);-- -- | Run an 'OW' computation.- ;- runOW :: forall a. (forall s. OW s a) -> a;- runOW uw = (\(MkOW st) -> evalState st 0) uw;-- -- | Generate a new 'OpenWitness' in 'OW'.- ;- newOpenWitnessOW :: forall s a. OW s (OpenWitness s a);- newOpenWitnessOW = MkOW (StateT (\val -> Identity (MkOpenWitness val,val+1)));-- -- | Run an 'OW' computation in 'IO'.- ;- owToIO :: OW RealWorld a -> IO a;- owToIO (MkOW st) = modifyMVar ioWitnessSource (\start -> let- {- (a,count) = runState st start;- } in return (count,a));-- -- | An unsafe hack to generate 'IOWitness' values.- -- This is safe if you use a different integer each time, and if @a@ is a single type.- ;- unsafeIOWitnessFromInteger :: Integer -> IOWitness a;- unsafeIOWitnessFromInteger = MkOpenWitness;-- -- | An unsafe hack to generate 'IOWitness' values.- -- This is safe if you use a different string each time (and 'hashString' doesn't collide), and if @a@ is a single type.- ;- unsafeIOWitnessFromString :: String -> IOWitness a;- unsafeIOWitnessFromString = unsafeIOWitnessFromInteger . fromIntegral . hash;-- -- | Template Haskell function to declare 'IOWitness' values.- ;- iowitness :: TypeQ -> Q Exp;- iowitness qt = do- {- t <- qt;- _ <- forM (freevarsType t) (\v -> reportError ("Type variable "++(show v)++" free in iowitness type"));- l <- location;- rnd :: Integer <- runIO randomIO;- key <- return ((showLoc l) ++ "/" ++ (show rnd));- keyExpr <- return (LitE (StringL key));- untypedWitExpr <- [| unsafeIOWitnessFromString $(return keyExpr) |];- [| $(return untypedWitExpr) :: IOWitness $(return t) |];- } where- {- showLoc :: Loc -> String;- showLoc l = (loc_filename l) ++ "=" ++ (loc_package l) ++ ":" ++ (loc_module l) ++ (show (loc_start l)) ++ (show (loc_end l));-- unionList :: (Eq a) => [[a]] -> [a];- unionList [] = [];- unionList (l:ls) = union l (unionList ls);-- bindingvarTVB :: TyVarBndr -> Name;- bindingvarTVB (PlainTV n) = n;- bindingvarTVB (KindedTV n _) = n;-- freevarsType :: Language.Haskell.TH.Type -> [Name];- freevarsType (ForallT tvbs ps t) =- (union (freevarsType t) (unionList (fmap freevarsType ps))) \\ (fmap bindingvarTVB tvbs);- freevarsType (VarT name) = [name];- freevarsType (AppT t1 t2) = union (freevarsType t1) (freevarsType t2);- freevarsType (SigT t _) = freevarsType t;- freevarsType _ = [];- };-}
− Data/OpenWitness/Dynamic.hs
@@ -1,56 +0,0 @@--- | This is an approximate re-implementation of "Data.Dynamic" using open witnesses.-module Data.OpenWitness.Dynamic where-{-{-- import Data.Witness;- import Data.OpenWitness.OpenRep;- import Data.OpenWitness.Typeable;-- -- * The @Dynamic@ type- ;-- type Dynamic = Any OpenRep;-- -- * Converting to and from @Dynamic@- ;-- toDyn :: Typeable a => a -> Dynamic;- toDyn = MkAny rep;-- fromDyn :: Typeable a => Dynamic -> a -> a;- fromDyn dyn def = case fromDynamic dyn of- {- Just a -> a;- _ -> def;- };-- fromDynamic :: forall a. Typeable a => Dynamic -> Maybe a;- fromDynamic (MkAny uq a) = do- {- MkEqualType <- testEquality uq (rep :: OpenRep a);- return a;- };-- -- * Applying functions of dynamic type- ;-- dynApply :: Dynamic -> Dynamic -> Maybe Dynamic;- dynApply (MkAny (ApplyOpenRep (ApplyOpenRep1 repFn' rx') ry) f) (MkAny rx x) = do- {- MkEqualType <- matchOpenRep2 repFn' (rep2 :: OpenRep2 (->));- MkEqualType <- testEquality rx' rx;- return (MkAny ry (f x));- };- dynApply _ _ = Nothing;-- dynApp :: Dynamic -> Dynamic -> Dynamic;- dynApp a b = case (dynApply a b) of- {- Just d -> d;- _ -> error "Type error in dynamic application.\nCan't apply function to argument";- };-- dynTypeRep :: Dynamic -> TypeRep;- dynTypeRep (MkAny r _) = MkAnyWitness r;--}-}
− Data/OpenWitness/Exception.hs
@@ -1,48 +0,0 @@-{-# LANGUAGE DeriveDataTypeable #-}-{-# OPTIONS -fno-warn-unused-matches #-}-module Data.OpenWitness.Exception-(- Exn, declexn, throw, catch-) where-{- import Data.OpenWitness;- import Data.Witness;- import Data.Maybe;- import Data.Typeable;- import Language.Haskell.TH;- import qualified Control.Exception as CE (Exception,throw,catch);- import Prelude(IO,Show(..));-- -- | A key to match exceptions. The type variable is the data the exception carries.- ;- newtype Exn (e :: *) = MkExn (IOWitness e);-- instance TestEquality Exn where- {- testEquality (MkExn a) (MkExn b) = testEquality a b;- };-- newtype ExnException = MkExnException (Any Exn) deriving Typeable;-- -- | Template Haskell function to declare 'Exn' exception keys.- ;- declexn :: TypeQ -> Q Exp;- declexn te = [| MkExn $(iowitness te) |];-- instance Show ExnException where- {- show _ = "ExnException";- };-- instance CE.Exception ExnException;-- throw :: Exn e -> e -> a;- throw exn e = CE.throw (MkExnException (MkAny exn e));-- catch :: IO a -> Exn e -> (e -> IO a) -> IO a;- catch foo exn catcher = CE.catch foo (\ex@(MkExnException cell) -> case matchAny exn cell of- {- Just e -> catcher e;- _ -> CE.throw ex;- });-}
− Data/OpenWitness/OpenRep.hs
@@ -1,70 +0,0 @@-module Data.OpenWitness.OpenRep where-{--- import Data.Witness;--- import Data.OpenWitness;--- import Data.Maybe;-{-- data T2 (a :: * -> * -> *);-- data OpenRep2 p where- {- SimpleOpenRep2 :: IOWitness (T2 p) -> OpenRep2 p;--- ApplyOpenRep2 :: OpenRep3 p -> OpenRep a -> OpenRep2 (p a);- };-- matchOpenRep2 :: OpenRep2 a -> OpenRep2 b -> Maybe (EqualType (T2 a) (T2 b));- matchOpenRep2 (SimpleOpenRep2 wa) (SimpleOpenRep2 wb) = testEquality wa wb;-{-- matchOpenRep2 (ApplyOpenRep1 tfa ta) (ApplyOpenRep1 tfb tb) = do- {- MkEqualType <- matchOpenRep2 tfa tfb;- MkEqualType <- testEquality ta tb;- return MkEqualType;- };- matchOpenRep2 _ _ = Nothing;--}-- data T1 (a :: * -> *);-- data OpenRep1 p where- {- SimpleOpenRep1 :: IOWitness (T1 p) -> OpenRep1 p;- ApplyOpenRep1 :: OpenRep2 p -> OpenRep a -> OpenRep1 (p a);- };-- matchOpenRep1 :: OpenRep1 a -> OpenRep1 b -> Maybe (EqualType (T1 a) (T1 b));- matchOpenRep1 (SimpleOpenRep1 wa) (SimpleOpenRep1 wb) = testEquality wa wb;- matchOpenRep1 (ApplyOpenRep1 tfa ta) (ApplyOpenRep1 tfb tb) = do- {- MkEqualType <- matchOpenRep2 tfa tfb;- MkEqualType <- testEquality ta tb;- return MkEqualType;- };- matchOpenRep1 _ _ = Nothing;--}--{-- data OpenRep :: k -> * where- {- SimpleOpenRep :: IOWitness a -> OpenRep a;- ApplyOpenRep :: OpenRep p -> OpenRep a -> OpenRep (p a);- };-- instance TestEquality OpenRep where- {- testEquality (SimpleOpenRep wa) (SimpleOpenRep wb) = testEquality wa wb;- testEquality (ApplyOpenRep tfa ta) (ApplyOpenRep tfb tb) = do- {- MkEqualType <- testEquality tfa tfb;- MkEqualType <- testEquality ta tb;- return MkEqualType;- };- testEquality _ _ = Nothing;- };-- instance Eq1 OpenRep where- {- equals1 r1 r2 = isJust (testEquality r1 r2);- };--}-}
− Data/OpenWitness/ST.hs
@@ -1,59 +0,0 @@--- | This is an approximate re-implementation of "Control.Monad.ST" and "Data.STRef" using open witnesses.-module Data.OpenWitness.ST-(- -- * The @ST@ Monad- ST,runST,fixST,- -- * Converting @ST@ to @OW@ and @IO@- stToOW,RealWorld,stToIO,- -- * STRefs- STRef,newSTRef,readSTRef,writeSTRef,modifySTRef-) where-{- import Data.OpenWitness;- import Data.Witness.WitnessDict;- import Control.Monad.Trans.State;- import Control.Monad.Trans.Class;- import Control.Monad.Fix;-- type ST s = StateT (WitnessDict (OpenWitness s)) (OW s);-- stToOW :: ST s a -> OW s a;- stToOW st = evalStateT st emptyWitnessDict;-- runST :: (forall s . ST s a) -> a;- runST st = runOW (stToOW st);-- fixST :: (a -> ST s a) -> ST s a;- fixST = mfix;-- type STRef = OpenWitness;-- newSTRef :: a -> ST s (STRef s a);- newSTRef a = do- {- wit <- lift newOpenWitnessOW;- dict <- get;- put (witnessDictAdd wit a dict);- return wit;- };-- readSTRef :: STRef s a -> ST s a;- readSTRef key = do- {- dict <- get;- case witnessDictLookup key dict of- {- Just a -> return a;- _ -> fail "ref not found";- };- };-- writeSTRef :: forall s a. STRef s a -> a -> ST s ();- writeSTRef key newa = modify (witnessDictReplace key newa);-- modifySTRef :: forall s a. STRef s a -> (a -> a) -> ST s ();- modifySTRef key amap = modify (witnessDictModify key amap);-- stToIO :: ST RealWorld a -> IO a;- stToIO = owToIO . stToOW;-}
− Data/OpenWitness/Typeable.hs
@@ -1,102 +0,0 @@--- | This is an approximate re-implementation of "Data.Typeable" using open witnesses.-module Data.OpenWitness.Typeable where-{-{-- import Data.OpenWitness.OpenRep;- import Data.OpenWitness;- import Data.Witness;-- -- | types of kind @*@ with a representation- ;- class Typeable a where- {- rep :: OpenRep a;- };-- -- | types of kind @* -> *@ with a representation- ;- class Typeable1 t where- {- rep1 :: OpenRep1 t;- };-- -- | types of kind @* -> * -> *@ with a representation- ;- class Typeable2 t where- {- rep2 :: OpenRep2 t;- };-- instance (Typeable1 f,Typeable a) => Typeable (f a) where- {- rep = ApplyOpenRep rep1 rep;- };-- instance (Typeable2 f,Typeable a) => Typeable1 (f a) where- {- rep1 = ApplyOpenRep1 rep2 rep;- };-- instance Typeable2 (->) where- {- rep2 = SimpleOpenRep2 $(iowitness [t|T2 (->)|]);- };-- cast :: forall a b. (Typeable a,Typeable b) => a -> Maybe b;- cast a = do- {- MkEqualType :: EqualType a b <- testEquality rep rep;- return a;- };-- gcast :: forall a b c. (Typeable a,Typeable b) => c a -> Maybe (c b);- gcast ca = do- {- MkEqualType :: EqualType a b <- testEquality rep rep;- return ca;- };-- -- | represents a type of kind @*@- ;- type TypeRep = AnyWitness OpenRep;-- typeOf :: forall t. (Typeable t) => t -> TypeRep;- typeOf _ = MkAnyWitness (rep :: OpenRep t);-- -- | represents a type of kind @* -> *@- ;- type TypeRep1 = AnyWitness1 OpenRep1;-- typeOf1 :: forall t a. (Typeable1 t) => t a -> TypeRep1;- typeOf1 _ = MkAnyWitness1 (rep1 :: OpenRep1 t);-- -- | represents a type of kind @* -> * -> *@- ;- type TypeRep2 = AnyWitness2 OpenRep2;-- typeOf2 :: forall t a b. (Typeable2 t) => t a b -> TypeRep2;- typeOf2 _ = MkAnyWitness2 (rep2 :: OpenRep2 t);-- -- | given representations of @a@ and @b@, make a representation of @a -> b@- ;- mkFunTy :: TypeRep -> TypeRep -> TypeRep;- mkFunTy (MkAnyWitness ta) (MkAnyWitness tb) = MkAnyWitness (ApplyOpenRep (ApplyOpenRep1 (rep2 :: OpenRep2 (->)) ta) tb);-- -- | given representations of @a -> b@ and @a@, make a representation of @b@ (otherwise not)- ;- funResultTy :: TypeRep -> TypeRep -> Maybe TypeRep;- funResultTy (MkAnyWitness (ApplyOpenRep (ApplyOpenRep1 repFn' ta') tb')) (MkAnyWitness ta) = do- {- MkEqualType <- matchOpenRep2 repFn' (rep2 :: OpenRep2 (->));- MkEqualType <- testEquality ta' ta;- return (MkAnyWitness tb');- };- funResultTy _ _ = Nothing;-- mkAppTy :: TypeRep1 -> TypeRep -> TypeRep;- mkAppTy (MkAnyWitness1 tf) (MkAnyWitness ta) = MkAnyWitness (ApplyOpenRep tf ta);-- mkAppTy1 :: TypeRep2 -> TypeRep -> TypeRep1;- mkAppTy1 (MkAnyWitness2 tf) (MkAnyWitness ta) = MkAnyWitness1 (ApplyOpenRep1 tf ta);--}-}
LICENSE view
@@ -1,4 +1,4 @@-open-witness is Copyright (c) Ashley Yakeley, 2007-2008.+open-witness is Copyright (c) Ashley Yakeley, 2007-2017. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
open-witness.cabal view
@@ -1,6 +1,6 @@ cabal-version: >=1.14 name: open-witness-version: 0.3.1+version: 0.4 x-follows-version-policy: license: BSD3 license-file: LICENSE@@ -17,7 +17,7 @@ build-type: Simple library- hs-source-dirs: .+ hs-source-dirs: src default-language: Haskell2010 default-extensions: MultiParamTypeClasses@@ -30,20 +30,49 @@ TemplateHaskell GeneralizedNewtypeDeriving GADTs- PolyKinds ScopedTypeVariables+ TypeInType+ ConstraintKinds+ UndecidableInstances build-depends:- base >= 4.8 && < 5,+ base >= 4.9.1 && < 5, random, template-haskell, transformers, hashable,- witness >= 0.3+ constraints,+ witness == 0.4 exposed-modules:+ Data.Type.Heterogeneous Data.OpenWitness+ Data.OpenWitness.TypeRep+ Data.OpenWitness.Typeable Data.OpenWitness.Dynamic Data.OpenWitness.Exception- Data.OpenWitness.OpenRep Data.OpenWitness.ST- Data.OpenWitness.Typeable+ Data.OpenWitness.Instance ghc-options: -Wall++test-suite tests+ type: exitcode-stdio-1.0+ hs-source-dirs: test+ default-language: Haskell2010+ default-extensions:+ RankNTypes+ EmptyDataDecls+ GeneralizedNewtypeDeriving+ ScopedTypeVariables+ GADTs+ FlexibleContexts+ MultiParamTypeClasses+ TemplateHaskell+ build-depends:+ base,+ mtl,+ witness,+ open-witness,+ tasty,+ tasty-hunit+ main-is: Main.hs+ other-modules:+ Object
+ src/Data/OpenWitness.hs view
@@ -0,0 +1,144 @@+{-# OPTIONS -fno-warn-name-shadowing #-}+module Data.OpenWitness+(+ OpenWitness,+ RealWorld,IOWitness,newIOWitness,+ OW,newOpenWitnessOW,runOW,owToIO,+-- unsafeIOWitnessFromInteger,+-- unsafeIOWitnessFromString,+ iowitness+) where+{+ import Prelude;+ import Data.Kind;+ import Data.List;+ import System.Random;+ import Language.Haskell.TH;+ import Unsafe.Coerce;+ import System.IO.Unsafe (unsafePerformIO);+ import Control.Concurrent.MVar;+ import Control.Monad.Fix;+ import Control.Monad.Trans.State;+ import Data.Functor.Identity;+ import Data.Traversable;+ import Data.Hashable;+ import Data.Witness;+ import Data.Type.Heterogeneous;+++ unsafeSameType :: HetEq a b;+ unsafeSameType = unsafeCoerce ReflH;++ -- | A witness type that can witness to any type.+ -- But values cannot be constructed; they can only be generated in 'IO' and certain other monads.+ ;+ newtype OpenWitness :: * -> forall (k :: *). k -> * where+ {+ MkOpenWitness :: Integer -> OpenWitness s a;+ } deriving Eq;++ instance TestHetEquality (OpenWitness s) where+ {+ testHetEquality (MkOpenWitness ua) (MkOpenWitness ub) =+ if ua == ub then Just unsafeSameType else Nothing;+ };++ instance TestEquality (OpenWitness s) where+ {+ testEquality wa wb = fmap homoHetEq $ testHetEquality wa wb;+ };++ -- | The @s@ type for running 'OW' in 'IO'.+ ;+ data RealWorld;++ -- | An 'OpenWitness' for 'IO'.+ ;+ type IOWitness = OpenWitness RealWorld;++ ioWitnessSource :: MVar Integer;+ {-# NOINLINE ioWitnessSource #-};+ ioWitnessSource = unsafePerformIO (newMVar 0);++ -- | Generate a new 'IOWitness' in 'IO'.+ ;+ newIOWitness :: forall a. IO (IOWitness a);+ newIOWitness = do+ {+ val <- takeMVar ioWitnessSource;+ putMVar ioWitnessSource (val + 1);+ return (MkOpenWitness val);+ };++ type OWState = Integer;++ -- | A runnable monad in which 'OpenWitness' values can be generated.+ -- The @s@ parameter plays the same role as it does in 'ST', preventing 'OpenWitness' values from one run being used in another.+ ;+ newtype OW s a = MkOW (State OWState a) deriving (Functor,Applicative,Monad,MonadFix);++ -- | Run an 'OW' computation.+ ;+ runOW :: forall a. (forall s. OW s a) -> a;+ runOW uw = (\(MkOW st) -> evalState st 0) uw;++ -- | Generate a new 'OpenWitness' in 'OW'.+ ;+ newOpenWitnessOW :: forall s a. OW s (OpenWitness s a);+ newOpenWitnessOW = MkOW (StateT (\val -> Identity (MkOpenWitness val,val+1)));++ -- | Run an 'OW' computation in 'IO'.+ ;+ owToIO :: OW RealWorld a -> IO a;+ owToIO (MkOW st) = modifyMVar ioWitnessSource (\start -> let+ {+ (a,count) = runState st start;+ } in return (count,a));++ -- | An unsafe hack to generate 'IOWitness' values.+ -- This is safe if you use a different integer each time, and if @a@ is a single type.+ ;+ unsafeIOWitnessFromInteger :: Integer -> IOWitness a;+ unsafeIOWitnessFromInteger = MkOpenWitness;++ -- | An unsafe hack to generate 'IOWitness' values.+ -- This is safe if you use a different string each time (and 'hashString' doesn't collide), and if @a@ is a single type.+ ;+ unsafeIOWitnessFromString :: String -> IOWitness a;+ unsafeIOWitnessFromString = unsafeIOWitnessFromInteger . fromIntegral . hash;++ -- | Template Haskell function to declare 'IOWitness' values.+ ;+ iowitness :: TypeQ -> Q Exp;+ iowitness qt = do+ {+ t <- qt;+ _ <- forM (freevarsType t) (\v -> reportError ("Type variable "++(show v)++" free in iowitness type"));+ l <- location;+ rnd :: Integer <- runIO randomIO;+ key <- return ((showLoc l) ++ "/" ++ (show rnd));+ keyExpr <- return (LitE (StringL key));+ untypedWitExpr <- [| unsafeIOWitnessFromString $(return keyExpr) |];+ [| $(return untypedWitExpr) :: IOWitness $(return t) |];+ } where+ {+ showLoc :: Loc -> String;+ showLoc l = (loc_filename l) ++ "=" ++ (loc_package l) ++ ":" ++ (loc_module l) ++ (show (loc_start l)) ++ (show (loc_end l));++ unionList :: (Eq a) => [[a]] -> [a];+ unionList [] = [];+ unionList (l:ls) = union l (unionList ls);++ bindingvarTVB :: TyVarBndr -> Name;+ bindingvarTVB (PlainTV n) = n;+ bindingvarTVB (KindedTV n _) = n;++ freevarsType :: Language.Haskell.TH.Type -> [Name];+ freevarsType (ForallT tvbs ps t) =+ (union (freevarsType t) (unionList (fmap freevarsType ps))) \\ (fmap bindingvarTVB tvbs);+ freevarsType (VarT name) = [name];+ freevarsType (AppT t1 t2) = union (freevarsType t1) (freevarsType t2);+ freevarsType (SigT t _) = freevarsType t;+ freevarsType _ = [];+ };+}
+ src/Data/OpenWitness/Dynamic.hs view
@@ -0,0 +1,56 @@+-- | This is an approximate re-implementation of "Data.Dynamic" using open witnesses.+module Data.OpenWitness.Dynamic where+{+ import Data.Kind;+ import Data.Witness;+ import Data.Type.Heterogeneous;+ import Data.OpenWitness.TypeRep;+ import Data.OpenWitness.Typeable;++ -- * The @Dynamic@ type+ ;++ type Dynamic = Any TypeRep;++ -- * Converting to and from @Dynamic@+ ;++ toDyn :: forall (a :: *). Typeable a => a -> Dynamic;+ toDyn = MkAny typeRep;++ fromDyn :: Typeable a => Dynamic -> a -> a;+ fromDyn dyn def = case fromDynamic dyn of+ {+ Just a -> a;+ _ -> def;+ };++ fromDynamic :: forall (a :: *). Typeable a => Dynamic -> Maybe a;+ fromDynamic (MkAny uq a) = do+ {+ Refl <- testEquality uq (typeRep :: TypeRep a);+ return a;+ };++ -- * Applying functions of dynamic type+ ;++ dynApply :: Dynamic -> Dynamic -> Maybe Dynamic;+ dynApply (MkAny (ApplyTypeRep (ApplyTypeRep repFn' rx') ry) f) (MkAny rx x) = do+ {+ ReflH <- testHetEquality repFn' (typeRep :: TypeRep (->));+ ReflH <- testHetEquality rx' rx;+ return (MkAny ry (f x));+ };+ dynApply _ _ = Nothing;++ dynApp :: Dynamic -> Dynamic -> Dynamic;+ dynApp a b = case (dynApply a b) of+ {+ Just d -> d;+ _ -> error "Type error in dynamic application.\nCan't apply function to argument";+ };++ dynTypeRep :: Dynamic -> AnyWitness (TypeRep :: * -> *);+ dynTypeRep (MkAny r _) = MkAnyWitness r;+}
+ src/Data/OpenWitness/Exception.hs view
@@ -0,0 +1,49 @@+{-# LANGUAGE DeriveDataTypeable #-}+{-# OPTIONS -fno-warn-unused-matches #-}+module Data.OpenWitness.Exception+(+ Exn, declexn, throw, catch+) where+{+ import Data.Kind;+ import Data.OpenWitness;+ import Data.Witness;+ import Data.Maybe;+ import Data.Typeable;+ import Language.Haskell.TH;+ import qualified Control.Exception as CE (Exception,throw,catch);+ import Prelude(IO,Show(..));++ -- | A key to match exceptions. The type variable is the data the exception carries.+ ;+ newtype Exn (e :: *) = MkExn (IOWitness e);++ instance TestEquality Exn where+ {+ testEquality (MkExn a) (MkExn b) = testEquality a b;+ };++ newtype ExnException = MkExnException (Any Exn) deriving Typeable;++ -- | Template Haskell function to declare 'Exn' exception keys.+ ;+ declexn :: TypeQ -> Q Exp;+ declexn te = [| MkExn $(iowitness te) |];++ instance Show ExnException where+ {+ show _ = "ExnException";+ };++ instance CE.Exception ExnException;++ throw :: Exn e -> e -> a;+ throw exn e = CE.throw (MkExnException (MkAny exn e));++ catch :: IO a -> Exn e -> (e -> IO a) -> IO a;+ catch foo exn catcher = CE.catch foo (\ex@(MkExnException cell) -> case matchAny exn cell of+ {+ Just e -> catcher e;+ _ -> CE.throw ex;+ });+}
+ src/Data/OpenWitness/Instance.hs view
@@ -0,0 +1,17 @@+module Data.OpenWitness.Instance where+{+ import Data.Kind;+ import Data.Constraint;+ import Data.Type.Heterogeneous;+ import Data.OpenWitness.TypeRep;++ data Instance = forall (t :: Constraint). t => MkInstance (TypeRep t);++ findInstance :: [Instance] -> TypeRep t -> Maybe (Dict t);+ findInstance [] _ = Nothing;+ findInstance (MkInstance ti:ii) t = case testHetEquality ti t of+ {+ Just ReflH -> Just Dict;+ Nothing -> findInstance ii t;+ };+}
+ src/Data/OpenWitness/ST.hs view
@@ -0,0 +1,59 @@+-- | This is an approximate re-implementation of "Control.Monad.ST" and "Data.STRef" using open witnesses.+module Data.OpenWitness.ST+(+ -- * The @ST@ Monad+ ST,runST,fixST,+ -- * Converting @ST@ to @OW@ and @IO@+ stToOW,RealWorld,stToIO,+ -- * STRefs+ STRef,newSTRef,readSTRef,writeSTRef,modifySTRef+) where+{+ import Data.OpenWitness;+ import Data.Witness.WitnessDict;+ import Control.Monad.Trans.State;+ import Control.Monad.Trans.Class;+ import Control.Monad.Fix;++ type ST s = StateT (WitnessDict (OpenWitness s)) (OW s);++ stToOW :: ST s a -> OW s a;+ stToOW st = evalStateT st emptyWitnessDict;++ runST :: (forall s . ST s a) -> a;+ runST st = runOW (stToOW st);++ fixST :: (a -> ST s a) -> ST s a;+ fixST = mfix;++ type STRef = OpenWitness;++ newSTRef :: a -> ST s (STRef s a);+ newSTRef a = do+ {+ wit <- lift newOpenWitnessOW;+ dict <- get;+ put (witnessDictAdd wit a dict);+ return wit;+ };++ readSTRef :: STRef s a -> ST s a;+ readSTRef key = do+ {+ dict <- get;+ case witnessDictLookup key dict of+ {+ Just a -> return a;+ _ -> fail "ref not found";+ };+ };++ writeSTRef :: forall s a. STRef s a -> a -> ST s ();+ writeSTRef key newa = modify (witnessDictReplace key newa);++ modifySTRef :: forall s a. STRef s a -> (a -> a) -> ST s ();+ modifySTRef key amap = modify (witnessDictModify key amap);++ stToIO :: ST RealWorld a -> IO a;+ stToIO = owToIO . stToOW;+}
+ src/Data/OpenWitness/TypeRep.hs view
@@ -0,0 +1,36 @@+module Data.OpenWitness.TypeRep where+{+ import Data.Kind;+ import Data.Maybe;+ import Data.Witness;+ import Data.OpenWitness;+ import Data.Type.Heterogeneous;++ data TypeRep :: forall (k :: *). k -> * where+ {+ SimpleTypeRep :: forall (k :: *) (a :: k). IOWitness a -> TypeRep a;+ ApplyTypeRep :: forall (k1 :: *) (k2 :: *) (p :: k1 -> k2) (a :: k1). TypeRep p -> TypeRep a -> TypeRep (p a);+ };++ instance TestHetEquality TypeRep where+ {+ testHetEquality (SimpleTypeRep wa) (SimpleTypeRep wb) = testHetEquality wa wb;+ testHetEquality (ApplyTypeRep tfa ta) (ApplyTypeRep tfb tb) = do+ {+ ReflH <- testHetEquality tfa tfb;+ ReflH <- testHetEquality ta tb;+ return ReflH;+ };+ testHetEquality _ _ = Nothing;+ };++ instance TestEquality TypeRep where+ {+ testEquality wa wb = fmap homoHetEq $ testHetEquality wa wb;+ };++ instance Eq1 TypeRep where+ {+ equals1 r1 r2 = isJust (testHetEquality r1 r2);+ };+}
+ src/Data/OpenWitness/Typeable.hs view
@@ -0,0 +1,120 @@+-- | This is an approximate re-implementation of "Data.Typeable" using open witnesses.+module Data.OpenWitness.Typeable where+{+ import Data.Kind;+ import Data.OpenWitness.TypeRep;+ import Data.OpenWitness;+ import Data.Witness;++ -- | types of kind @*@ with a representation+ ;+ class Typeable (a :: k) where+ {+ typeRep :: TypeRep a;+ };++ instance (Typeable (f :: k1 -> k2),Typeable (a :: k1)) => Typeable (f a) where+ {+ typeRep = ApplyTypeRep typeRep typeRep;+ };++ instance Typeable Type where+ {+ typeRep = SimpleTypeRep $(iowitness [t|Type|]);+ };++ type Fun = (->);++ instance Typeable (->) where+ {+ typeRep = SimpleTypeRep $(iowitness [t|Fun|]);+ };++ instance Typeable Constraint where+ {+ typeRep = SimpleTypeRep $(iowitness [t|Constraint|]);+ };++ instance Typeable TypeRep where+ {+ typeRep = SimpleTypeRep $(iowitness [t|TypeRep|]);+ };++ instance Typeable Typeable where+ {+ typeRep = SimpleTypeRep $(iowitness [t|Typeable|]);+ };++ instance Typeable () where+ {+ typeRep = SimpleTypeRep $(iowitness [t|()|]);+ };++ instance Typeable (,) where+ {+ typeRep = SimpleTypeRep $(iowitness [t|(,)|]);+ };++ instance Typeable Either where+ {+ typeRep = SimpleTypeRep $(iowitness [t|Either|]);+ };++ instance Typeable Maybe where+ {+ typeRep = SimpleTypeRep $(iowitness [t|Maybe|]);+ };++ instance Typeable [] where+ {+ typeRep = SimpleTypeRep $(iowitness [t|[]|]);+ };++ instance Typeable Bool where+ {+ typeRep = SimpleTypeRep $(iowitness [t|Bool|]);+ };++ instance Typeable Char where+ {+ typeRep = SimpleTypeRep $(iowitness [t|Char|]);+ };++ instance Typeable Int where+ {+ typeRep = SimpleTypeRep $(iowitness [t|Int|]);+ };++ cast :: forall (a :: *) (b :: *). (Typeable a,Typeable b) => a -> Maybe b;+ cast a = do+ {+ Refl :: a :~: b <- testEquality typeRep typeRep;+ return a;+ };++ gcast :: forall (k :: *) (a :: k) (b :: k) (c :: k -> *). (Typeable a,Typeable b) => c a -> Maybe (c b);+ gcast ca = do+ {+ Refl :: a :~: b <- testEquality typeRep typeRep;+ return ca;+ };++ -- | given representations of @a@ and @b@, make a representation of @a -> b@+ ;+ mkFunTy :: TypeRep a -> TypeRep b -> TypeRep (a -> b);+ mkFunTy ta tb = ApplyTypeRep (ApplyTypeRep (typeRep :: TypeRep (->)) ta) tb;++ -- | given representations of @a -> b@ and @a@, make a representation of @b@ (otherwise not)+ ;+ funResultTy :: TypeRep (a -> b) -> TypeRep a -> Maybe (TypeRep b);+ funResultTy (ApplyTypeRep (ApplyTypeRep repFn' ta') tb') ta = do+ {+ Refl <- testEquality repFn' (typeRep :: TypeRep (->));+ Refl <- testEquality ta' ta;+ return tb';+ };+ funResultTy _ _ = Nothing;++ mkAppTy :: forall (k1 :: *) (k2 :: *) (f :: k1 -> k2) (a :: k1). TypeRep f -> TypeRep a -> TypeRep (f a);+ mkAppTy = ApplyTypeRep;+}
+ src/Data/Type/Heterogeneous.hs view
@@ -0,0 +1,20 @@+module Data.Type.Heterogeneous where+{+ import Data.Kind;+ import Data.Type.Equality;++ data HetEq (a :: ka) (b :: kb) where+ {+ ReflH :: forall (k :: *) (t :: k). HetEq t t;+ };++ -- | somewhat awkwardly named+ ;+ homoHetEq :: forall (k :: *) (a :: k) (b :: k). HetEq a b -> a :~: b;+ homoHetEq ReflH = Refl;++ class TestHetEquality (w :: forall k. k -> *) where+ {+ testHetEquality :: forall (ka :: *) (a :: ka) (kb :: *) (b :: kb). w a -> w b -> Maybe (HetEq a b);+ };+}
+ test/Main.hs view
@@ -0,0 +1,63 @@+{-# LANGUAGE TemplateHaskell #-}+module Main where+{+ import Data.OpenWitness.ST;+ import Data.OpenWitness.Exception;+ import Prelude;+ import Test.Tasty;+ import Test.Tasty.HUnit;++ stuff :: ST s [Int];+ stuff = do+ {+ ra <- newSTRef 3;+ a1 <- readSTRef ra;+ rb <- newSTRef 4;+ b1 <- readSTRef rb;+ writeSTRef ra 5;+ a2 <- readSTRef ra;+ writeSTRef rb 7;+ b2 <- readSTRef rb;+ return [a1,b1,a2,b2];+ };++ testST :: TestTree;+ testST = testCase "ST" $ assertEqual "vals" [3,4,5,7] $ runST stuff;++ intExn :: Exn Int;+ intExn = $(declexn [t|Int|]);+ stringExn :: Exn String;+ stringExn = $(declexn [t|String|]);++ data Caught = NotCaught | IntCaught Int | StringCaught String deriving (Eq,Show);++ getCaught :: IO a -> IO Caught;+ getCaught f = ((do+ {+ _ <- f;+ return NotCaught;+ }+ `catch` intExn) (\x -> return (IntCaught x))+ `catch` stringExn) (\x -> return (StringCaught x));++ testCaught :: String -> Caught -> IO a -> TestTree;+ testCaught name expected f = testCase name $ do+ {+ result <- getCaught f;+ assertEqual "caught" expected result;+ };++ tests :: TestTree;+ tests = testGroup "test"+ [+ testST,+ testCaught "return" NotCaught $ return "hello",+ testCaught "throw intExn 3" (IntCaught 3) $ throw intExn 3,+ testCaught "throw stringExn text" (StringCaught "text") $ throw stringExn "text",+ testCaught "throw intExn 67" (IntCaught 67) $ throw intExn 67,+ testCaught "throw stringExn str" (StringCaught "str") $ throw stringExn "str"+ ];++ main :: IO ();+ main = defaultMain tests;+}
+ test/Object.hs view
@@ -0,0 +1,24 @@+module Object where+{+ import Data.Witness;+ import Data.OpenWitness;++ data Object s = forall a. MkObject (OpenWitness s a) a;++ matchObject :: OpenWitness s b -> Object s -> Maybe b;+ matchObject uqb (MkObject uqa a) = do+ {+ MkEqualType <- testEquality uqa uqb;+ return a;+ };++ makeConversions :: OpenWitness s b -> (b -> Object s,Object s -> Maybe b);+ makeConversions wit = (MkObject wit,matchObject wit);++ getConversions :: OW s (b -> Object s,Object s -> Maybe b);+ getConversions = do+ {+ wit <- newOpenWitnessOW;+ return (makeConversions wit);+ };+}