rank1dynamic 0.1.0.2 → 0.4.3
raw patch · 7 files changed
Files
- ChangeLog +54/−0
- LICENSE +1/−0
- Setup.hs +0/−2
- rank1dynamic.cabal +43/−15
- src/Data/Rank1Dynamic.hs +32/−22
- src/Data/Rank1Typeable.hs +112/−89
- tests/test.hs +133/−0
+ ChangeLog view
@@ -0,0 +1,54 @@+2025-02-04 Laurent P. René de Cotret <laurent.decotret@outlook.com> 0.4.3++* Ported test suite to use `tasty` rather than `test-framework`.+* Removed unused test dependencies (#467)++2024-09-03 Laurent P. René de Cotret <laurent.decotret@outlook.com> 0.4.2++* Bumped dependency bounds to support GHC 8.10.7 - GHC 9.10.1+* Updated links to point to Distributed Haskell monorepo++2020-10-24 Facundo Domínguez <facundo.dominguez@tweag.io> 0.4.1++* Support ghc-8.6.5 and ghc-8.8.4++2017-08-22 Facundo Domínguez <facundo.dominguez@tweag.io> 0.4.0++* Add compatibility with ghc-8.2.1.+* Drop support for ghc-7.6 and ghc-7.8.++2016-05-31 Facundo Domínguez <facundo.dominguez@tweag.io> 0.3.3.0++* Add compatibility with ghc-8.+* Update bug report url in cabal file.++2016-02-18 Facundo Domínguez <facundo.dominguez@tweag.io> 0.3.2.0++* Stop testing ghc-7.4 and test ghc-7.10.+* Add unsafeToDynamic.++2016-01-25 Facundo Domínguez <facundo.dominguez@tweag.io> 0.3.1.1++* Push HUnit upper bound.++2015-06-15 Facundo Domínguez <facundo.dominguez@tweag.io> 0.2.1.0++* Loosen upper bound of ghc-prim.++2014-05-30 Tim Watson <watson.timothy@gmail.com> 0.2.0.0++* Fix funResultTy so @funResultTy ANY _ = ANY@+* Ensure the result of funResultTy is consistent with unification+* Bump binary version to include 0.7.*++2012-11-22 Edsko de Vries <edsko@well-typed.com> 0.1.0.2++* Relax package bounds to allow for Binary 0.6++2012-09-27 Edsko de Vries <edsko@well-typed.com> 0.1.0.1++* Relax lower bound of base to 4.4 (ghc 7.2)++2012-08-10 Edsko de Vries <edsko@well-typed.com> 0.1.0.0++* Initial release.
LICENSE view
@@ -1,4 +1,5 @@ Copyright (c) 2012, Edsko de Vries+Copyright (c) 2015, Tweag I/O Limited All rights reserved.
− Setup.hs
@@ -1,2 +0,0 @@-import Distribution.Simple-main = defaultMain
rank1dynamic.cabal view
@@ -1,28 +1,56 @@+cabal-version: 3.0 Name: rank1dynamic-Version: 0.1.0.2+Version: 0.4.3 Synopsis: Like Data.Dynamic/Data.Typeable but with support for rank-1 polymorphic types-Description: "Data.Typeable" and "Data.Dynamic" only support monomorphic types. +Description: "Data.Typeable" and "Data.Dynamic" only support monomorphic types. In this package we provide similar functionality but with- support for rank-1 polymorphic types. -Homepage: http://github.com/haskell-distributed/distributed-process-License: BSD3+ support for rank-1 polymorphic types.+Homepage: http://haskell-distributed.github.com+License: BSD-3-Clause License-File: LICENSE Author: Edsko de Vries-Maintainer: edsko@well-typed.com-Copyright: Well-Typed LLP+maintainer: The Distributed Haskell team+Bug-Reports: https://github.com/haskell-distributed/distributed-process/issues+Copyright: Well-Typed LLP, Tweag I/O Limited Category: Data Build-Type: Simple-Cabal-Version: >=1.8+extra-doc-files: ChangeLog +source-repository head+ Type: git+ Location: https://github.com/haskell-distributed/distributed-process+ SubDir: packages/rank1dynamic++common warnings+ ghc-options: -Wall+ -Wcompat+ -Widentities+ -Wincomplete-uni-patterns+ -Wincomplete-record-updates+ -Wredundant-constraints+ -fhide-source-paths+ -Wpartial-fields+ -Wunused-packages+ Library+ import: warnings Exposed-Modules: Data.Rank1Dynamic, Data.Rank1Typeable- Build-Depends: base >= 4.4 && < 4.7,- ghc-prim >= 0.2 && < 0.4,- binary >= 0.5 && < 0.7 + Build-Depends: base >= 4.14 && < 5,+ binary >= 0.8 && < 0.9 HS-Source-Dirs: src- GHC-Options: -Wall- Extensions: EmptyDataDecls,+ default-language: Haskell2010+ Default-Extensions: EmptyDataDecls, DeriveDataTypeable,- ViewPatterns,- CPP+ ViewPatterns++Test-Suite TestRank1Dynamic+ import: warnings+ Type: exitcode-stdio-1.0+ Main-Is: test.hs+ Build-Depends: base >= 4.14 && < 5,+ rank1dynamic,+ tasty >= 1.5 && <1.6,+ tasty-hunit >=0.10 && <0.11,+ default-language: Haskell2010+ HS-Source-Dirs: tests
src/Data/Rank1Dynamic.hs view
@@ -5,42 +5,42 @@ -- These examples correspond to the 'Data.Rank1Typeable.isInstanceOf' examples -- in "Data.Rank1Typeable". ----- > > do f <- fromDynamic (toDynamic (even :: Int -> Bool)) ; return $ (f :: Int -> Int) 0 +-- > > do f <- fromDynamic (toDynamic (even :: Int -> Bool)) ; return $ (f :: Int -> Int) 0 -- > Left "Cannot unify Int and Bool"--- > +-- > -- > > do f <- fromDynamic (toDynamic (const 1 :: ANY -> Int)) ; return $ (f :: Int -> Int) 0 -- > Right 1--- > +-- > -- > > do f <- fromDynamic (toDynamic (unsafeCoerce :: ANY1 -> ANY2)) ; return $ (f :: Int -> Int) 0 -- > Right 0--- > +-- > -- > > do f <- fromDynamic (toDynamic (id :: ANY -> ANY)) ; return $ (f :: Int -> Bool) 0 -- > Left "Cannot unify Bool and Int"--- > +-- > -- > > do f <- fromDynamic (toDynamic (undefined :: ANY)) ; return $ (f :: Int -> Int) 0 -- > Right *** Exception: Prelude.undefined--- > +-- > -- > > do f <- fromDynamic (toDynamic (id :: ANY -> ANY)) ; return $ (f :: Int) -- > Left "Cannot unify Int and ->" -- -- [Examples of dynApply]--- +-- -- These examples correspond to the 'Data.Rank1Typeable.funResultTy' examples -- in "Data.Rank1Typeable". -- -- > > do app <- toDynamic (id :: ANY -> ANY) `dynApply` toDynamic True ; f <- fromDynamic app ; return $ (f :: Bool) -- > Right True--- > +-- > -- > > do app <- toDynamic (const :: ANY -> ANY1 -> ANY) `dynApply` toDynamic True ; f <- fromDynamic app ; return $ (f :: Int -> Bool) 0 -- > Right True--- > +-- > -- > > do app <- toDynamic (($ True) :: (Bool -> ANY) -> ANY) `dynApply` toDynamic (id :: ANY -> ANY) ; f <- fromDynamic app ; return (f :: Bool) -- > Right True--- > +-- > -- > > app <- toDynamic (const :: ANY -> ANY1 -> ANY) `dynApply` toDynamic (id :: ANY -> ANY) ; f <- fromDynamic app ; return $ (f :: Int -> Bool -> Bool) 0 True -- > Right True--- > --- > > do app <- toDynamic ((\f -> f . f) :: (ANY -> ANY) -> ANY -> ANY) `dynApply` toDynamic (even :: Int -> Bool) ; f <- fromDynamic app ; return (f :: ()) +-- >+-- > > do app <- toDynamic ((\f -> f . f) :: (ANY -> ANY) -> ANY -> ANY) `dynApply` toDynamic (even :: Int -> Bool) ; f <- fromDynamic app ; return (f :: ()) -- > Left "Cannot unify Int and Bool" -- -- [Using toDynamic]@@ -48,40 +48,41 @@ -- When using polymorphic values you need to give an explicit type annotation: -- -- > > toDynamic id--- > +-- > -- > <interactive>:46:1: -- > Ambiguous type variable `a0' in the constraint: -- > (Typeable a0) arising from a use of `toDynamic' -- > Probable fix: add a type signature that fixes these type variable(s) -- > In the expression: toDynamic id -- > In an equation for `it': it = toDynamic id--- +-- -- versus -- -- > > toDynamic (id :: ANY -> ANY) -- > <<ANY -> ANY>>--- +-- -- Note that these type annotation are checked by ghc like any other: -- -- > > toDynamic (id :: ANY -> ANY1)--- > +-- > -- > <interactive>:45:12: -- > Couldn't match expected type `V1' with actual type `V0' -- > Expected type: ANY -> ANY1 -- > Actual type: ANY -> ANY -- > In the first argument of `toDynamic', namely `(id :: ANY -> ANY1)' -- > In the expression: toDynamic (id :: ANY -> ANY1)-module Data.Rank1Dynamic +module Data.Rank1Dynamic ( Dynamic , toDynamic , fromDynamic , TypeError , dynTypeRep , dynApply+ , unsafeToDynamic ) where -import qualified GHC.Prim as GHC (Any)-import Data.Rank1Typeable +import qualified GHC.Exts as GHC (Any)+import Data.Rank1Typeable ( Typeable , TypeRep , typeOf@@ -95,16 +96,25 @@ data Dynamic = Dynamic TypeRep GHC.Any instance Show Dynamic where- showsPrec _ (Dynamic t _) = showString "<<" . shows t . showString ">>" + showsPrec _ (Dynamic t _) = showString "<<" . shows t . showString ">>" --- | Introduce a dynamic value +-- | Introduce a dynamic value toDynamic :: Typeable a => a -> Dynamic toDynamic x = Dynamic (typeOf x) (unsafeCoerce x) +-- | Construct a dynamic value with a user-supplied type rep+--+-- This function is unsafe because we have no way of verifying that the+-- provided type representation matches the value.+--+-- Since 0.3.2.0.+unsafeToDynamic :: TypeRep -> a -> Dynamic+unsafeToDynamic typ x = Dynamic typ (unsafeCoerce x)+ -- | Eliminate a dynamic value fromDynamic :: Typeable a => Dynamic -> Either TypeError a fromDynamic (Dynamic t v) =- case unsafeCoerce v of + case unsafeCoerce v of r -> case typeOf r `isInstanceOf` t of Left err -> Left err Right () -> Right r
src/Data/Rank1Typeable.hs view
@@ -1,7 +1,7 @@ -- | Runtime type representation of terms with support for rank-1 polymorphic -- types with type variables of kind *. ----- The essence of this module is that we use the standard 'Typeable' +-- The essence of this module is that we use the standard 'Typeable' -- representation of "Data.Typeable" but we introduce a special (empty) data -- type 'TypVar' which represents type variables. 'TypVar' is indexed by an -- arbitrary other data type, giving you an unbounded number of type variables;@@ -12,23 +12,23 @@ -- > -- We CANNOT use a term of type 'Int -> Bool' as 'Int -> Int' -- > > typeOf (undefined :: Int -> Int) `isInstanceOf` typeOf (undefined :: Int -> Bool) -- > Left "Cannot unify Int and Bool"--- > +-- > -- > -- We CAN use a term of type 'forall a. a -> Int' as 'Int -> Int' -- > > typeOf (undefined :: Int -> Int) `isInstanceOf` typeOf (undefined :: ANY -> Int) -- > Right ()--- > +-- > -- > -- We CAN use a term of type 'forall a b. a -> b' as 'forall a. a -> a' -- > > typeOf (undefined :: ANY -> ANY) `isInstanceOf` typeOf (undefined :: ANY -> ANY1) -- > Right ()--- > +-- > -- > -- We CANNOT use a term of type 'forall a. a -> a' as 'forall a b. a -> b' -- > > typeOf (undefined :: ANY -> ANY1) `isInstanceOf` typeOf (undefined :: ANY -> ANY) -- > Left "Cannot unify Succ and Zero"--- > +-- > -- > -- We CAN use a term of type 'forall a. a' as 'forall a. a -> a' -- > > typeOf (undefined :: ANY -> ANY) `isInstanceOf` typeOf (undefined :: ANY) -- > Right ()--- > +-- > -- > -- We CANNOT use a term of type 'forall a. a -> a' as 'forall a. a' -- > > typeOf (undefined :: ANY) `isInstanceOf` typeOf (undefined :: ANY -> ANY) -- > Left "Cannot unify Skolem and ->"@@ -37,14 +37,14 @@ -- -- [Examples of funResultTy] ----- > -- Apply fn of type (forall a. a -> a) to arg of type Bool gives Bool +-- > -- Apply fn of type (forall a. a -> a) to arg of type Bool gives Bool -- > > funResultTy (typeOf (undefined :: ANY -> ANY)) (typeOf (undefined :: Bool)) -- > Right Bool--- > +-- > -- > -- Apply fn of type (forall a b. a -> b -> a) to arg of type Bool gives forall a. a -> Bool -- > > funResultTy (typeOf (undefined :: ANY -> ANY1 -> ANY)) (typeOf (undefined :: Bool)) -- > Right (ANY -> Bool) -- forall a. a -> Bool--- > +-- > -- > -- Apply fn of type (forall a. (Bool -> a) -> a) to argument of type (forall a. a -> a) gives Bool -- > > funResultTy (typeOf (undefined :: (Bool -> ANY) -> ANY)) (typeOf (undefined :: ANY -> ANY)) -- > Right Bool@@ -56,14 +56,14 @@ -- > -- Cannot apply function of type (forall a. (a -> a) -> a -> a) to arg of type (Int -> Bool) -- > > funResultTy (typeOf (undefined :: (ANY -> ANY) -> (ANY -> ANY))) (typeOf (undefined :: Int -> Bool)) -- > Left "Cannot unify Int and Bool"-module Data.Rank1Typeable - ( -- * Basic types +{-# LANGUAGE BangPatterns #-}+module Data.Rank1Typeable+ ( -- * Basic types TypeRep , typeOf , splitTyConApp , mkTyConApp- , underlyingTypeRep- -- * Operations on type representations + -- * Operations on type representations , isInstanceOf , funResultTy , TypeError@@ -98,65 +98,86 @@ import Prelude hiding (succ) import Control.Arrow ((***), second) import Control.Monad (void)-import Control.Applicative ((<$>))+import Data.Binary+import Data.Function (on) import Data.List (intersperse, isPrefixOf) import Data.Maybe (fromMaybe)-import Data.Typeable (Typeable, mkTyCon3)-import Data.Typeable.Internal (listTc, funTc, TyCon(TyCon), tyConName)-import Data.Binary (Binary(get, put))-import GHC.Fingerprint.Type (Fingerprint(..))-import qualified Data.Typeable as Typeable - ( TypeRep- , typeOf- , splitTyConApp- , mkTyConApp- )+import Data.Typeable ( Typeable )+import qualified Data.Typeable as T+import GHC.Fingerprint +tcList, tcFun :: TyCon+tcList = fst $ splitTyConApp $ typeOf [()]+tcFun = fst $ splitTyConApp $ typeOf (\() -> ())+ -------------------------------------------------------------------------------- -- The basic type -- -------------------------------------------------------------------------------- -- | Dynamic type representation with support for rank-1 types-newtype TypeRep = TypeRep { - -- | Return the underlying standard ("Data.Typeable") type representation- underlyingTypeRep :: Typeable.TypeRep - }+data TypeRep+ = TRCon TyCon+ | TRApp {-# UNPACK #-} !Fingerprint TypeRep TypeRep +data TyCon = TyCon+ { tyConFingerprint :: {-# UNPACK #-} !Fingerprint+ , tyConPackage :: String+ , tyConModule :: String+ , tyConName :: String+ }++-- | The fingerprint of a TypeRep+typeRepFingerprint :: TypeRep -> Fingerprint+typeRepFingerprint (TRCon c) = tyConFingerprint c+typeRepFingerprint (TRApp fp _ _) = fp+ -- | Compare two type representations------ For base >= 4.6 this compares fingerprints, but older versions of base--- have a bug in the fingerprint construction --- (<http://hackage.haskell.org/trac/ghc/ticket/5962>)+instance Eq TyCon where+ (==) = (==) `on` tyConFingerprint+ instance Eq TypeRep where-#if ! MIN_VERSION_base(4,6,0)- (splitTyConApp -> (c1, ts1)) == (splitTyConApp -> (c2, ts2)) =- c1 == c2 && all (uncurry (==)) (zip ts1 ts2)-#else- t1 == t2 = underlyingTypeRep t1 == underlyingTypeRep t2-#endif+ (==) = (==) `on` typeRepFingerprint --- Binary instance for 'TypeRep', avoiding orphan instances+--- Binary instance for 'TypeRep', avoiding orphan instances instance Binary TypeRep where- put (splitTyConApp -> (TyCon (Fingerprint hi lo) package modul name, ts)) = do- put hi - put lo- put package- put modul- put name+ put (splitTyConApp -> (tc, ts)) = do+ put $ tyConPackage tc+ put $ tyConModule tc+ put $ tyConName tc put ts get = do- hi <- get- lo <- get package <- get modul <- get name <- get ts <- get- return $ mkTyConApp (TyCon (Fingerprint hi lo) package modul name) ts+ return $ mkTyConApp (mkTyCon3 package modul name) ts -- | The type representation of any 'Typeable' term typeOf :: Typeable a => a -> TypeRep-typeOf = TypeRep . Typeable.typeOf+typeOf = trTypeOf . T.typeOf +-- | Conversion from Data.Typeable.TypeRep to Data.Rank1Typeable.TypeRep+trTypeOf :: T.TypeRep -> TypeRep+trTypeOf t = let (c, ts) = T.splitTyConApp t+ in foldl mkTRApp (TRCon $ fromTypeableTyCon c) $ map trTypeOf ts+ where+ fromTypeableTyCon c =+ TyCon (T.tyConFingerprint c)+ (T.tyConPackage c)+ (T.tyConModule c)+ (T.tyConName c)++-- | Applies a TypeRep to another.+mkTRApp :: TypeRep -> TypeRep -> TypeRep+mkTRApp t0 t1 = TRApp fp t0 t1+ where+ fp = fingerprintFingerprints [typeRepFingerprint t0, typeRepFingerprint t1]++mkTyCon3 :: String -> String -> String -> TyCon+mkTyCon3 pkg m name = TyCon fp pkg m name+ where+ fp = fingerprintFingerprints [ fingerprintString s | s <- [pkg, m, name] ]+ -------------------------------------------------------------------------------- -- Constructors/destructors (views) -- --------------------------------------------------------------------------------@@ -164,16 +185,16 @@ -- | Split a type representation into the application of -- a type constructor and its argument splitTyConApp :: TypeRep -> (TyCon, [TypeRep])-splitTyConApp t = - let (c, ts) = Typeable.splitTyConApp (underlyingTypeRep t)- in (c, map TypeRep ts)+splitTyConApp = go []+ where+ go xs (TRCon c) = (c, xs)+ go xs (TRApp _ t0 t1) = go (t1 : xs) t0 -- | Inverse of 'splitTyConApp' mkTyConApp :: TyCon -> [TypeRep] -> TypeRep-mkTyConApp c ts - = TypeRep (Typeable.mkTyConApp c (map underlyingTypeRep ts))+mkTyConApp c = foldl mkTRApp (TRCon c) -isTypVar :: TypeRep -> Maybe Var +isTypVar :: TypeRep -> Maybe Var isTypVar (splitTyConApp -> (c, [t])) | c == typVar = Just t isTypVar _ = Nothing @@ -190,7 +211,7 @@ -- Type variables -- -------------------------------------------------------------------------------- -data TypVar a deriving Typeable +data TypVar a deriving Typeable data Skolem a deriving Typeable data Zero deriving Typeable data Succ a deriving Typeable@@ -206,7 +227,7 @@ type V8 = Succ V7 type V9 = Succ V8 -type ANY = TypVar V0 +type ANY = TypVar V0 type ANY1 = TypVar V1 type ANY2 = TypVar V2 type ANY3 = TypVar V3@@ -224,18 +245,17 @@ -- | If 'isInstanceOf' fails it returns a type error type TypeError = String --- | @t1 `isInstanceOf` t2@ checks if @t1@ is an instance of @t2@ -isInstanceOf :: TypeRep -> TypeRep -> Either TypeError () +-- | @t1 `isInstanceOf` t2@ checks if @t1@ is an instance of @t2@+isInstanceOf :: TypeRep -> TypeRep -> Either TypeError () isInstanceOf t1 t2 = void (unify (skolemize t1) t2) -- | @funResultTy t1 t2@ is the type of the result when applying a function -- of type @t1@ to an argument of type @t2@-funResultTy :: TypeRep -> TypeRep -> Either TypeError TypeRep -funResultTy (splitTyConApp -> (fc, [farg, fres])) x | fc == funTc = do - s <- unify (alphaRename "f" farg) (alphaRename "x" x)- return (normalize (subst s (alphaRename "f" fres)))-funResultTy f _ = - Left $ show f ++ " is not a function"+funResultTy :: TypeRep -> TypeRep -> Either TypeError TypeRep+funResultTy t1 t2 = do+ let anyTy = mkTypVar $ typeOf (undefined :: V0)+ s <- unify (alphaRename "f" t1) $ mkTyConApp tcFun [alphaRename "x" t2, anyTy]+ return $ normalize $ subst s anyTy -------------------------------------------------------------------------------- -- Alpha-renaming and normalization --@@ -251,7 +271,7 @@ tvars (isTypVar -> Just x) = [x] tvars (splitTyConApp -> (_, ts)) = concatMap tvars ts -normalize :: TypeRep -> TypeRep +normalize :: TypeRep -> TypeRep normalize t = subst (zip (tvars t) anys) t where anys :: [TypeRep]@@ -261,7 +281,7 @@ succ = mkTyConApp succTyCon . (:[]) zero :: TypeRep- zero = mkTyConApp zeroTyCon [] + zero = mkTyConApp zeroTyCon [] mkTyCon :: String -> TyCon mkTyCon = mkTyCon3 "rank1typeable" "Data.Rank1Typeable"@@ -281,38 +301,38 @@ type Var = TypeRep skolemize :: TypeRep -> TypeRep-skolemize (isTypVar -> Just x) = mkTyConApp skolem [x] +skolemize (isTypVar -> Just x) = mkTyConApp skolem [x] skolemize (splitTyConApp -> (c, ts)) = mkTyConApp c (map skolemize ts) occurs :: Var -> TypeRep -> Bool-occurs x (isTypVar -> Just x') = x == x' +occurs x (isTypVar -> Just x') = x == x' occurs x (splitTyConApp -> (_, ts)) = any (occurs x) ts subst :: Substitution -> TypeRep -> TypeRep subst s (isTypVar -> Just x) = fromMaybe (mkTypVar x) (lookup x s) subst s (splitTyConApp -> (c, ts)) = mkTyConApp c (map (subst s) ts) -unify :: TypeRep - -> TypeRep - -> Either TypeError Substitution +unify :: TypeRep+ -> TypeRep+ -> Either TypeError Substitution unify = \t1 t2 -> go [] [(t1, t2)] where- go :: Substitution - -> [Equation] - -> Either TypeError Substitution - go acc [] = + go :: Substitution+ -> [Equation]+ -> Either TypeError Substitution+ go acc [] = return acc go acc ((t1, t2) : eqs) | t1 == t2 = -- Note: equality check is fast go acc eqs go acc ((isTypVar -> Just x, t) : eqs) =- if x `occurs` t + if x `occurs` t then Left "Occurs check"- else go ((x, t) : map (second $ subst [(x, t)]) acc) + else go ((x, t) : map (second $ subst [(x, t)]) acc) (map (subst [(x, t)] *** subst [(x, t)]) eqs) go acc ((t, isTypVar -> Just x) : eqs) = go acc ((mkTypVar x, t) : eqs)- go acc ((splitTyConApp -> (c1, ts1), splitTyConApp -> (c2, ts2)) : eqs) = - if c1 /= c2 + go acc ((splitTyConApp -> (c1, ts1), splitTyConApp -> (c2, ts2)) : eqs) =+ if c1 /= c2 then Left $ "Cannot unify " ++ show c1 ++ " and " ++ show c2 else go acc (zip ts1 ts2 ++ eqs) @@ -320,18 +340,21 @@ -- Pretty-printing -- -------------------------------------------------------------------------------- +instance Show TyCon where+ showsPrec _ c = showString (tyConName c)+ instance Show TypeRep where showsPrec p (splitTyConApp -> (tycon, tys)) = case tys of [] -> showsPrec p tycon- [anyIdx -> Just i] | tycon == typVar -> showString "ANY" . showIdx i - [x] | tycon == listTc -> + [anyIdx -> Just i] | tycon == typVar -> showString "ANY" . showIdx i+ [x] | tycon == tcList -> showChar '[' . shows x . showChar ']'- [a,r] | tycon == funTc -> - showParen (p > 8) $ showsPrec 9 a - . showString " -> " + [a,r] | tycon == tcFun ->+ showParen (p > 8) $ showsPrec 9 a+ . showString " -> " . showsPrec 8 r- xs | isTupleTyCon tycon -> + xs | isTupleTyCon tycon -> showTuple xs _ -> showParen (p > 9) $ showsPrec p tycon@@ -344,16 +367,16 @@ showArgs :: Show a => [a] -> ShowS showArgs [] = id showArgs [a] = showsPrec 10 a-showArgs (a:as) = showsPrec 10 a . showString " " . showArgs as +showArgs (a:as) = showsPrec 10 a . showString " " . showArgs as -anyIdx :: TypeRep -> Maybe Int +anyIdx :: TypeRep -> Maybe Int anyIdx (splitTyConApp -> (c, [])) | c == zeroTyCon = Just 0 anyIdx (splitTyConApp -> (c, [t])) | c == succTyCon = (+1) <$> anyIdx t anyIdx _ = Nothing showTuple :: [TypeRep] -> ShowS showTuple args = showChar '('- . foldr (.) id ( intersperse (showChar ',') + . foldr (.) id ( intersperse (showChar ',') $ map (showsPrec 10) args ) . showChar ')'
+ tests/test.hs view
@@ -0,0 +1,133 @@+{-# LANGUAGE CPP #-}+import Data.Rank1Dynamic+import Data.Rank1Typeable++import Test.Tasty+import Test.Tasty.HUnit+import Unsafe.Coerce++funKindStr :: String+#if defined(MIN_VERSION_GLASGOW_HASKELL) && MIN_VERSION_GLASGOW_HASKELL(9,0,0,0)+funKindStr = "FUN"+#elif __GLASGOW_HASKELL__ >= 804+funKindStr = "->"+#else+funKindStr = "(->)"+#endif+++main :: IO ()+main = defaultMain (testGroup "rank1dynamic" tests)++tests :: [TestTree]+tests =+ [ testGroup "Examples of isInstanceOf"+ [ testCase "CANNOT use a term of type 'Int -> Bool' as 'Int -> Int'" $+ typeOf (undefined :: Int -> Int) `isInstanceOf` typeOf (undefined :: Int -> Bool)+ @?= Left "Cannot unify Int and Bool"++ , testCase "CAN use a term of type 'forall a. a -> Int' as 'Int -> Int'" $+ typeOf (undefined :: Int -> Int) `isInstanceOf` typeOf (undefined :: ANY -> Int)+ @?= Right ()++ , testCase "CAN use a term of type 'forall a b. a -> b' as 'forall a. a -> a'" $+ typeOf (undefined :: ANY -> ANY) `isInstanceOf` typeOf (undefined :: ANY -> ANY1)+ @?= Right ()++ , testCase "CANNOT use a term of type 'forall a. a -> a' as 'forall a b. a -> b'" $+ typeOf (undefined :: ANY -> ANY1) `isInstanceOf` typeOf (undefined :: ANY -> ANY)+ @?= Left "Cannot unify Succ and Zero"++ , testCase "CAN use a term of type 'forall a. a' as 'forall a. a -> a'" $+ typeOf (undefined :: ANY -> ANY) `isInstanceOf` typeOf (undefined :: ANY)+ @?= Right ()++ , testCase "CANNOT use a term of type 'forall a. a -> a' as 'forall a. a'" $+ typeOf (undefined :: ANY) `isInstanceOf` typeOf (undefined :: ANY -> ANY)+ @?= Left ("Cannot unify Skolem and " ++ funKindStr)+ ]++ , testGroup "Examples of funResultTy"+ [ testCase "Apply fn of type (forall a. a -> a) to arg of type Bool gives Bool" $+ show (funResultTy (typeOf (undefined :: ANY -> ANY)) (typeOf (undefined :: Bool)))+ @?= "Right Bool"++ , testCase "Apply fn of type (forall a b. a -> b -> a) to arg of type Bool gives forall a. a -> Bool" $+ show (funResultTy (typeOf (undefined :: ANY -> ANY1 -> ANY)) (typeOf (undefined :: Bool)))+ @?= "Right (ANY -> Bool)" -- forall a. a -> Bool++ , testCase "Apply fn of type (forall a. (Bool -> a) -> a) to argument of type (forall a. a -> a) gives Bool" $+ show (funResultTy (typeOf (undefined :: (Bool -> ANY) -> ANY)) (typeOf (undefined :: ANY -> ANY)))+ @?= "Right Bool"++ , testCase "Apply fn of type (forall a b. a -> b -> a) to arg of type (forall a. a -> a) gives (forall a b. a -> b -> b)" $+ show (funResultTy (typeOf (undefined :: ANY -> ANY1 -> ANY)) (typeOf (undefined :: ANY1 -> ANY1)))+ @?= "Right (ANY -> ANY1 -> ANY1)"++ , testCase "Cannot apply function of type (forall a. (a -> a) -> a -> a) to arg of type (Int -> Bool)" $+ show (funResultTy (typeOf (undefined :: (ANY -> ANY) -> (ANY -> ANY))) (typeOf (undefined :: Int -> Bool)))+ @?= "Left \"Cannot unify Int and Bool\""+ ]++ , testGroup "Examples of fromDynamic"+ [ testCase "CANNOT use a term of type 'Int -> Bool' as 'Int -> Int'" $+ do f <- fromDynamic (toDynamic (even :: Int -> Bool))+ return $ (f :: Int -> Int) 0+ @?= Left "Cannot unify Int and Bool"++ , testCase "CAN use a term of type 'forall a. a -> Int' as 'Int -> Int'" $+ do f <- fromDynamic (toDynamic (const 1 :: ANY -> Int))+ return $ (f :: Int -> Int) 0+ @?= Right 1++ , testCase "CAN use a term of type 'forall a b. a -> b' as 'forall a. a -> a'" $+ do f <- fromDynamic (toDynamic (unsafeCoerce :: ANY1 -> ANY2))+ return $ (f :: Int -> Int) 0+ @?= Right 0++ , testCase "CANNOT use a term of type 'forall a. a -> a' as 'forall a b. a -> b'" $+ do f <- fromDynamic (toDynamic (id :: ANY -> ANY))+ return $ (f :: Int -> Bool) 0+ @?= Left "Cannot unify Bool and Int"++ , testCase "CAN use a term of type 'forall a. a' as 'forall a. a -> a'" $+ case do f <- fromDynamic (toDynamic (undefined :: ANY))+ return $ (f :: Int -> Int) 0+ of+ Right _ -> return ()+ result -> assertFailure $ "Expected 'Right _' but got '" ++ show result ++ "'"++ , testCase "CANNOT use a term of type 'forall a. a -> a' as 'forall a. a'" $+ do f <- fromDynamic (toDynamic (id :: ANY -> ANY)) ; return $ (f :: Int)+ @?= Left ("Cannot unify Int and " ++ funKindStr)+ ]++ , testGroup "Examples of dynApply"+ [ testCase "Apply fn of type (forall a. a -> a) to arg of type Bool gives Bool" $+ do app <- toDynamic (id :: ANY -> ANY) `dynApply` toDynamic True+ f <- fromDynamic app+ return $ (f :: Bool)+ @?= Right True++ , testCase "Apply fn of type (forall a b. a -> b -> a) to arg of type Bool gives forall a. a -> Bool" $+ do app <- toDynamic (const :: ANY -> ANY1 -> ANY) `dynApply` toDynamic True+ f <- fromDynamic app+ return $ (f :: Int -> Bool) 0+ @?= Right True++ , testCase "Apply fn of type (forall a. (Bool -> a) -> a) to argument of type (forall a. a -> a) gives Bool" $+ do app <- toDynamic (($ True) :: (Bool -> ANY) -> ANY) `dynApply` toDynamic (id :: ANY -> ANY)+ f <- fromDynamic app+ return (f :: Bool)+ @?= Right True++ , testCase "Apply fn of type (forall a b. a -> b -> a) to arg of type (forall a. a -> a) gives (forall a b. a -> b -> b)" $+ do app <- toDynamic (const :: ANY -> ANY1 -> ANY) `dynApply` toDynamic (id :: ANY -> ANY)+ f <- fromDynamic app ; return $ (f :: Int -> Bool -> Bool) 0 True+ @?= Right True++ , testCase "Cannot apply function of type (forall a. (a -> a) -> a -> a) to arg of type (Int -> Bool)" $+ do app <- toDynamic ((\f -> f . f) :: (ANY -> ANY) -> ANY -> ANY) `dynApply` toDynamic (even :: Int -> Bool) ; f <- fromDynamic app ; return (f :: ())+ @?= Left "Cannot unify Int and Bool"+ ]+ ]