packages feed

rank1dynamic 0.2.0.0 → 0.2.0.1

raw patch · 4 files changed

+337/−24 lines, 4 filesdep +HUnitdep +constraintsdep +rank1dynamicPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: HUnit, constraints, rank1dynamic, test-framework, test-framework-hunit

API changes (from Hackage documentation)

- Data.Rank1Typeable: data TypVar a
- Data.Rank1Typeable: instance Typeable1 Skolem
- Data.Rank1Typeable: instance Typeable1 Succ
- Data.Rank1Typeable: instance Typeable1 TypVar
+ Data.Rank1Typeable: instance Typeable Any
+ Data.Rank1Typeable: instance Typeable Skolem
+ Data.Rank1Typeable: instance Typeable Succ
+ Data.Rank1Typeable: instance Typeable T
+ Data.Rank1Typeable: type TypVar = Any T
- Data.Rank1Typeable: class Typeable a
+ Data.Rank1Typeable: class Typeable (a :: k)
- Data.Rank1Typeable: data Succ a
+ Data.Rank1Typeable: data Succ (a :: *)

Files

rank1dynamic.cabal view
@@ -1,5 +1,5 @@ Name:                rank1dynamic-Version:             0.2.0.0+Version:             0.2.0.1 Synopsis:            Like Data.Dynamic/Data.Typeable but with support for rank-1 polymorphic types Description:         "Data.Typeable" and "Data.Dynamic" only support monomorphic types.                       In this package we provide similar functionality but with@@ -28,7 +28,27 @@                        binary >= 0.5 && < 0.8   HS-Source-Dirs:      src   GHC-Options:         -Wall-  Extensions:          EmptyDataDecls,+  Extensions:          ConstraintKinds,+                       EmptyDataDecls,+                       ExistentialQuantification,                        DeriveDataTypeable,+                       KindSignatures,+                       PolyKinds,+                       RankNTypes,+                       StandaloneDeriving,                        ViewPatterns,                        CPP++Test-Suite TestRank1Dynamic+  Type:              exitcode-stdio-1.0+  Main-Is:           test.hs+  Build-Depends:     base >= 4.4 && < 5,+                     HUnit >= 1.2 && < 1.3,+                     rank1dynamic,+                     test-framework >= 0.6 && < 0.9,+                     test-framework-hunit >= 0.2.0 && < 0.4+  if impl(ghc >= 7.8)+    Build-Depends:   constraints >= 0.4 && < 0.5+  ghc-options:       -Wall -Werror+  Extensions:        CPP+  HS-Source-Dirs:    tests
src/Data/Rank1Dynamic.hs view
@@ -22,6 +22,13 @@ -- > -- > > do f <- fromDynamic (toDynamic (id :: ANY -> ANY)) ; return $ (f :: Int) -- > Left "Cannot unify Int and ->"+-- >+-- > > do f <- fromDynamic (toDynamic (reifyConstraints return :: Dict (Monad Maybe) -> Int -> Maybe Int))+-- >      return $ (abstractConstraints (f :: Dict (Monad Maybe) -> Int -> Maybe Int)) 0+-- > Right (Just 0)+--+-- Please, see @tests/test.hs@ for examples of how to write the higher-kinded+-- case in ghc versions earlier than 7.6.3. -- -- [Examples of dynApply] --
src/Data/Rank1Typeable.hs view
@@ -32,9 +32,32 @@ -- > -- 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 ->"+-- >+-- > -- We CAN use a term of type 'forall a. a -> m a' as 'Int -> Maybe Int'+-- > > typeOf (undefined :: Int -> Maybe Int)+-- >     `isInstanceOf` typeOf (undefined :: ANY1 -> ANY ANY1)+-- > Left "Cannot unify Skolem and ->"+-- >+-- > -- We CAN use a term of type 'forall a. Monad a => a -> m a' as 'Int -> Maybe Int'+-- > -- 'Dict' comes from "Data.Constraint" in the package "constraints".+-- > > typeOf ((\Dict -> return) :: Dict (Monad Maybe) -> Int -> Maybe Int)+-- >     `isInstanceOf` typeOf ((\Dict -> return) :: Dict (Monad ANY) -> ANY1 -> ANY ANY1)+-- > Right () -- -- (Admittedly, the quality of the type errors could be improved.) --+-- When using @-XPolyKinds@, the type signatures with higher-kinded variables+-- need to be given as+--+-- > (\Dict -> return) `asTypeOf` (undefined :: Dict (Monad ANY) -> ANY1 -> ANY ANY1)+--+-- or+--+-- > (\Dict -> return) :: Dict (Monad ANY) -> ANY1 -> ANY (ANY1 :: *)+--+-- Please, see @tests/test.hs@ for examples of how to write the higher-kinded+-- cases in ghc versions earlier than 7.8.3.+-- -- [Examples of funResultTy] -- -- > -- Apply fn of type (forall a. a -> a) to arg of type Bool gives Bool@@ -56,6 +79,7 @@ -- > -- 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"+{-# OPTIONS_GHC -fno-warn-orphans #-} module Data.Rank1Typeable   ( -- * Basic types     TypeRep@@ -102,9 +126,21 @@ import Data.List (intersperse, isPrefixOf) import Data.Maybe (fromMaybe) import Data.Typeable (Typeable, mkTyCon3)+#if !MIN_VERSION_base(4,7,0)+import Data.Typeable+  ( Typeable1(..)+  , Typeable2(..)+  , Typeable3(..)+  , Typeable4(..)+  , Typeable5(..)+  , Typeable6(..)+  , Typeable7(..)+  )+#endif import Data.Typeable.Internal (listTc, funTc, TyCon(TyCon), tyConName) import Data.Binary (Binary(get, put)) import GHC.Fingerprint.Type (Fingerprint(..))+import GHC.Exts(Any) import qualified Data.Typeable as Typeable   ( TypeRep   , typeOf@@ -173,16 +209,23 @@ mkTyConApp c ts   = TypeRep (Typeable.mkTyConApp c (map underlyingTypeRep ts)) -isTypVar :: TypeRep -> Maybe Var-isTypVar (splitTyConApp -> (c, [t])) | c == typVar = Just t-isTypVar _ = Nothing+isTypVarApp :: TypeRep -> Maybe (Var, [TypeRep])+isTypVarApp (splitTyConApp -> (c, (t0:t:ts)))+    | c == typVar && t0 == typTag = Just (t,ts)+isTypVarApp _ = Nothing -mkTypVar :: Var -> TypeRep-mkTypVar x = mkTyConApp typVar [x]+mkTypVarApp :: Var -> [TypeRep] -> TypeRep+mkTypVarApp x = mkTyConApp typVar . (typTag :) . (x :) +mkTyApp :: TypeRep -> [TypeRep] -> TypeRep+mkTyApp (splitTyConApp -> (c, ts)) = mkTyConApp c . (ts++)+ typVar :: TyCon typVar = let (c, _) = splitTyConApp (typeOf (undefined :: TypVar V0)) in c +typTag :: TypeRep+typTag = typeOf (undefined :: T)+ skolem :: TyCon skolem = let (c, _) = splitTyConApp (typeOf (undefined :: Skolem V0)) in c @@ -190,11 +233,42 @@ -- Type variables                                                             -- -------------------------------------------------------------------------------- -data TypVar a deriving Typeable-data Skolem a deriving Typeable-data Zero     deriving Typeable-data Succ a   deriving Typeable+-- | Internal tag to distinguish our uses of Any from user's.+data T               deriving Typeable +type TypVar = Any T+data Skolem (a :: *) deriving Typeable+data Zero            deriving Typeable+data Succ   (a :: *) deriving Typeable++#if MIN_VERSION_base(4,7,0)+deriving instance Typeable Any+#else+instance Typeable Any where+  typeOf _ = Typeable.mkTyConApp (mkTyCon3 "ghc-prim" "GHC.Prim" "Any") []++instance Typeable1 Any where+  typeOf1 _ = Typeable.mkTyConApp (mkTyCon3 "ghc-prim" "GHC.Prim" "Any") []++instance Typeable2 Any where+  typeOf2 _ = Typeable.mkTyConApp (mkTyCon3 "ghc-prim" "GHC.Prim" "Any") []++instance Typeable3 Any where+  typeOf3 _ = Typeable.mkTyConApp (mkTyCon3 "ghc-prim" "GHC.Prim" "Any") []++instance Typeable4 Any where+  typeOf4 _ = Typeable.mkTyConApp (mkTyCon3 "ghc-prim" "GHC.Prim" "Any") []++instance Typeable5 Any where+  typeOf5 _ = Typeable.mkTyConApp (mkTyCon3 "ghc-prim" "GHC.Prim" "Any") []++instance Typeable6 Any where+  typeOf6 _ = Typeable.mkTyConApp (mkTyCon3 "ghc-prim" "GHC.Prim" "Any") []++instance Typeable7 Any where+  typeOf7 _ = Typeable.mkTyConApp (mkTyCon3 "ghc-prim" "GHC.Prim" "Any") []+#endif+ type V0 = Zero type V1 = Succ V0 type V2 = Succ V1@@ -232,7 +306,7 @@ -- of type @t1@ to an argument of type @t2@ funResultTy :: TypeRep -> TypeRep -> Either TypeError TypeRep funResultTy t1 t2 = do-  let anyTy = mkTypVar $ typeOf (undefined :: V0)+  let anyTy = mkTypVarApp (typeOf (undefined :: V0)) []   s <- unify (alphaRename "f" t1) $ mkTyConApp funTc [alphaRename "x" t2, anyTy]   return $ normalize $ subst s anyTy @@ -241,20 +315,20 @@ --------------------------------------------------------------------------------  alphaRename :: String -> TypeRep -> TypeRep-alphaRename prefix (isTypVar -> Just x) =-  mkTypVar (mkTyConApp (mkTyCon prefix) [x])+alphaRename prefix (isTypVarApp -> Just (x,ts)) =+  mkTypVarApp (mkTyConApp (mkTyCon prefix) [x]) (map (alphaRename prefix) ts) alphaRename prefix (splitTyConApp -> (c, ts)) =   mkTyConApp c (map (alphaRename prefix) ts)  tvars :: TypeRep -> [Var]-tvars (isTypVar -> Just x)       = [x]+tvars (isTypVarApp -> Just (x, ts)) =  x : concatMap tvars ts tvars (splitTyConApp -> (_, ts)) = concatMap tvars ts  normalize :: TypeRep -> TypeRep normalize t = subst (zip (tvars t) anys) t   where     anys :: [TypeRep]-    anys = map mkTypVar (iterate succ zero)+    anys = map (flip mkTypVarApp []) (iterate succ zero)      succ :: TypeRep -> TypeRep     succ = mkTyConApp succTyCon . (:[])@@ -280,15 +354,16 @@ type Var          = TypeRep  skolemize :: TypeRep -> TypeRep-skolemize (isTypVar -> Just x)       = mkTyConApp skolem [x]-skolemize (splitTyConApp -> (c, ts)) = mkTyConApp c (map skolemize ts)+skolemize (isTypVarApp -> Just (x, ts)) = mkTyConApp skolem $ x : map skolemize ts+skolemize (splitTyConApp -> (c, ts))    = mkTyConApp c (map skolemize ts)  occurs :: Var -> TypeRep -> Bool-occurs x (isTypVar -> Just x')      = x == x'+occurs x (isTypVarApp -> Just (x', ts)) = x == x' || any (occurs x) ts 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 (isTypVarApp -> Just (x, ts)) =+     flip mkTyApp (map (subst s) ts) $ fromMaybe (mkTypVarApp x []) (lookup x s) subst s (splitTyConApp -> (c, ts)) = mkTyConApp c (map (subst s) ts)  unify :: TypeRep@@ -303,13 +378,23 @@       return acc     go acc ((t1, t2) : eqs) | t1 == t2 = -- Note: equality check is fast       go acc eqs-    go acc ((isTypVar -> Just x, t) : eqs) =+    go acc ((isTypVarApp -> Just (x, []), t) : eqs) =       if x `occurs` t         then Left "Occurs check"         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)+    -- The left-hand side of the equation is a type variable application.+    -- Decompose the right-hand side of the equation.+    go acc ((t1@(isTypVarApp -> Just (x, ts)), t2) : eqs) =+      let (t,ts') = case isTypVarApp t2 of+                      Just (x', ts'') -> (mkTypVarApp x' [], ts'')+                      Nothing        -> let (c,ts'') = splitTyConApp t2+                                         in (mkTyConApp c [], ts'')+       in if length ts == length ts'+            then go acc ((mkTypVarApp x [], t) : zip ts ts' ++ eqs)+            else Left $ "Cannot unify " ++ show t1 ++ " and " ++ show t2+    go acc ((t, isTypVarApp -> Just (x, ts)) : eqs) =+      go acc ((mkTypVarApp x ts, t) : eqs)     go acc ((splitTyConApp -> (c1, ts1), splitTyConApp -> (c2, ts2)) : eqs) =       if c1 /= c2         then Left $ "Cannot unify " ++ show c1 ++ " and " ++ show c2@@ -323,7 +408,11 @@   showsPrec p (splitTyConApp -> (tycon, tys)) =       case tys of         [] -> showsPrec p tycon-        [anyIdx -> Just i] | tycon == typVar -> showString "ANY" . showIdx i+        (t0 : (anyIdx -> Just i) : ts) | tycon == typVar && t0 == typTag ->+          if null ts+            then showString "ANY" . showIdx i+            else showParen (p > 9) $ showString "ANY" . showIdx i .+                                     showChar ' ' . showArgs ts         [x] | tycon == listTc ->           showChar '[' . shows x . showChar ']'         [a,r] | tycon == funTc ->
+ tests/test.hs view
@@ -0,0 +1,197 @@+#if !MIN_VERSION_base(4,7,0)+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE ExistentialQuantification #-}+#if !MIN_VERSION_base(4,6,0)+{-# LANGUAGE KindSignatures #-}+#endif+#endif+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++import Data.Rank1Typeable+import Data.Rank1Dynamic++#if MIN_VERSION_base(4,7,0)+import Data.Constraint (Dict(..))+#else+import qualified Data.Typeable as Typeable (Typeable(..),Typeable1(..), mkTyCon3, mkTyConApp)+#endif+import Test.HUnit hiding (Test)+import Test.Framework+import Test.Framework.Providers.HUnit+import Unsafe.Coerce+++main :: IO ()+main = defaultMain tests++#if MIN_VERSION_base(4,7,0)+deriving instance Typeable Monad+#else+data MonadDict m = Monad m => MonadDict++instance Typeable.Typeable1 m => Typeable (MonadDict m) where+  typeOf _ = Typeable.mkTyConApp (Typeable.mkTyCon3 "main" "Main" "MonadDict")+               [ Typeable.typeOf1 (undefined :: m a) ]++returnD :: MonadDict m -> a -> m a+returnD MonadDict = return+#endif++tests :: [Test]+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)+#if MIN_VERSION_base(4,7,0)+          @?= Left "Cannot unify Skolem and (->)"+#else+          @?= Left "Cannot unify Skolem and ->"+#endif++      , testCase "CAN use a term of type 'forall a. a -> m a' as 'Int -> Maybe Int'" $+          typeOf (undefined :: Int -> Maybe Int)+            `isInstanceOf`+#if MIN_VERSION_base(4,6,0)+               typeOf (undefined :: ANY1 -> ANY ANY1)+#else+               typeOf (undefined :: ANY1 -> ANY (ANY1 :: *))+#endif+          @?= Right ()++      , testCase "CAN use a term of type 'forall a. Monad a => a -> m a' as 'Int -> Maybe Int'" $+#if MIN_VERSION_base(4,7,0)+          typeOf ((\Dict -> return) :: Dict (Monad Maybe) -> Int -> Maybe Int)+            `isInstanceOf`+               typeOf ((\Dict -> return) :: Dict (Monad ANY) -> ANY1 -> ANY ANY1)+#else+          typeOf (returnD :: MonadDict Maybe -> Int -> Maybe Int)+            `isInstanceOf`+#if MIN_VERSION_base(4,6,0)+               typeOf (returnD :: MonadDict ANY -> ANY1 -> ANY ANY1)+#else+               typeOf (returnD :: MonadDict ANY -> ANY1 -> ANY (ANY1 :: *))+#endif+#endif+          @?= Right ()+      ]++  , 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)+#if MIN_VERSION_base(4,7,0)+          @?= Left "Cannot unify Int and (->)"+#else+          @?= Left "Cannot unify Int and ->"+#endif++      , testCase "CAN use a term of type 'forall a. Monad a => a -> m a' as 'Int -> Maybe Int'" $+#if MIN_VERSION_base(4,7,0)+          do f <- fromDynamic (toDynamic ((\Dict -> return) :: Dict (Monad Maybe) -> Int -> Maybe Int))+             return $ (f :: Dict (Monad Maybe) -> Int -> Maybe Int) Dict 0+#else+          do f <- fromDynamic (toDynamic (returnD :: MonadDict Maybe -> Int -> Maybe Int))+             return $ ((f :: MonadDict Maybe -> Int -> Maybe Int) MonadDict) 0+#endif+          @?= Right (Just 0)+      ]++  , 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"+      ]+  ]