data-reify 0.6.1 → 0.6.2
raw patch · 4 files changed
+139/−70 lines, 4 filesdep +hashabledep +unordered-containersPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: hashable, unordered-containers
API changes (from Hackage documentation)
- Data.Reify: instance Eq DynStableName
- Data.Reify.Graph: instance Show (e Int) => Show (Graph e)
+ Data.Reify: instance Data.Hashable.Class.Hashable Data.Reify.DynStableName
+ Data.Reify: instance GHC.Classes.Eq Data.Reify.DynStableName
+ Data.Reify: reifyGraphs :: (MuRef s, Traversable t) => t s -> IO (t (Graph (DeRef s)))
+ Data.Reify: type family DeRef a :: * -> *;
+ Data.Reify: }
+ Data.Reify.Graph: instance GHC.Show.Show (e GHC.Types.Int) => GHC.Show.Show (Data.Reify.Graph.Graph e)
- Data.Reify: class MuRef a where type family DeRef a :: * -> *
+ Data.Reify: class MuRef a where {
Files
- CHANGELOG.md +22/−1
- Data/Reify.hs +71/−35
- data-reify.cabal +41/−30
- test/Test2.hs +5/−4
CHANGELOG.md view
@@ -1,2 +1,23 @@+## 0.6.2 [2020.09.30]+* Use `HashMap`s and `IntSet`s internally for slightly better performance.+ ## 0.6.1-* Fixed warnings in GHC 7.10+* Fix warnings in GHC 7.10.++## 0.5+* Merge the mono-typed and dynamic version again, by using 'DynStableName', an+ unphantomized version of StableName.++## 0.4+* Use 'Int' as a synonym for 'Unique' rather than 'Data.Unique' for node ids,+ by popular demand.++## 0.3+* Provide two versions of 'MuRef', the mono-typed version, for trees of a+ single type, and the dynamic-typed version, for trees of different types.++## 0.2+* Use 'StableName's, making `data-reify` much faster.++## 0.1+* Use unsafe pointer compares.
Data/Reify.hs view
@@ -1,21 +1,30 @@-{-# LANGUAGE TypeFamilies, RankNTypes #-}+{-# LANGUAGE CPP, TypeFamilies, RankNTypes #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE BangPatterns #-} module Data.Reify ( MuRef(..), module Data.Reify.Graph,- reifyGraph+ reifyGraph,+ reifyGraphs ) where import Control.Applicative import Control.Concurrent.MVar -import Data.IntMap as M+import Data.HashMap.Lazy as M+import Data.Hashable as H import Data.Reify.Graph+import qualified Data.IntSet as S+#if !(MIN_VERSION_base(4,8,0))+import Data.Traversable+#endif import System.Mem.StableName -import Unsafe.Coerce- import Prelude+#if __GLASGOW_HASKELL__ < 708+import Unsafe.Coerce+#endif -- | 'MuRef' is a class that provided a way to reference into a specific type, -- and a way to map over the deferenced internals.@@ -23,9 +32,9 @@ class MuRef a where type DeRef a :: * -> * - mapDeRef :: (Applicative f) => - (forall b . (MuRef b, DeRef a ~ DeRef b) => b -> f u) - -> a + mapDeRef :: (Applicative f) =>+ (forall b . (MuRef b, DeRef a ~ DeRef b) => b -> f u)+ -> a -> f (DeRef a u) -- | 'reifyGraph' takes a data structure that admits 'MuRef', and returns a 'Graph' that contains@@ -35,55 +44,82 @@ reifyGraph m = do rt1 <- newMVar M.empty rt2 <- newMVar [] uVar <- newMVar 0- root <- findNodes rt1 rt2 uVar m- pairs <- readMVar rt2- return (Graph pairs root)+ reifyWithContext rt1 rt2 uVar m -findNodes :: (MuRef s) - => MVar (IntMap [(DynStableName,Int)]) - -> MVar [(Int,DeRef s Int)] +-- | 'reifyGraphs' takes a 'Traversable' container 't s' of a data structure 's'+-- admitting 'MuRef', and returns a 't (Graph (DeRef s))' with the graph nodes+-- resolved within the same context.+--+-- This allows for, e.g., a list of mutually recursive structures.+reifyGraphs :: (MuRef s, Traversable t) => t s -> IO (t (Graph (DeRef s)))+reifyGraphs coll = do rt1 <- newMVar M.empty+ uVar <- newMVar 0+ flip traverse coll $ \m -> do+ rt2 <- newMVar []+ reifyWithContext rt1 rt2 uVar m++reifyWithContext :: (MuRef s)+ => MVar (HashMap DynStableName Int)+ -> MVar [(Int,DeRef s Int)] -> MVar Int- -> s + -> s+ -> IO (Graph (DeRef s))+reifyWithContext rt1 rt2 uVar j = do+ root <- findNodes rt1 rt2 uVar S.empty j+ pairs <- readMVar rt2+ return (Graph pairs root)++findNodes :: (MuRef s)+ => MVar (HashMap DynStableName Int)+ -> MVar [(Int,DeRef s Int)]+ -> MVar Int+ -> S.IntSet+ -> s -> IO Int-findNodes rt1 rt2 uVar j | j `seq` True = do+findNodes rt1 rt2 uVar nodeSet !j = do st <- makeDynStableName j tab <- takeMVar rt1- case mylookup st tab of+ case M.lookup st tab of Just var -> do putMVar rt1 tab- return $ var- Nothing -> + if var `S.member` nodeSet+ then return var+ else do res <- mapDeRef (findNodes rt1 rt2 uVar (S.insert var nodeSet)) j+ tab' <- takeMVar rt2+ putMVar rt2 $ (var,res) : tab'+ return var+ Nothing -> do var <- newUnique uVar- putMVar rt1 $ M.insertWith (++) (hashDynStableName st) [(st,var)] tab- res <- mapDeRef (findNodes rt1 rt2 uVar) j+ putMVar rt1 $ M.insert st var tab+ res <- mapDeRef (findNodes rt1 rt2 uVar (S.insert var nodeSet)) j tab' <- takeMVar rt2 putMVar rt2 $ (var,res) : tab' return var-findNodes _ _ _ _ = error "findNodes: strictness seq function failed to return True" -mylookup :: DynStableName -> IntMap [(DynStableName,Int)] -> Maybe Int-mylookup h tab =- case M.lookup (hashDynStableName h) tab of- Just tab2 -> Prelude.lookup h [ (c,u) | (c,u) <- tab2 ]- Nothing -> Nothing- newUnique :: MVar Int -> IO Int newUnique var = do v <- takeMVar var let v' = succ v putMVar var v' return v'- --- Stable names that not use phantom types.++-- Stable names that do not use phantom types. -- As suggested by Ganesh Sittampalam.-data DynStableName = DynStableName (StableName ())+-- Note: GHC can't unpack these because of the existential+-- quantification, but there doesn't seem to be much+-- potential to unpack them anyway.+data DynStableName = forall a. DynStableName !(StableName a) -hashDynStableName :: DynStableName -> Int-hashDynStableName (DynStableName sn) = hashStableName sn+instance Hashable DynStableName where+ hashWithSalt s (DynStableName n) = hashWithSalt s n instance Eq DynStableName where- (DynStableName sn1) == (DynStableName sn2) = sn1 == sn2+#if __GLASGOW_HASKELL__ >= 708+ DynStableName m == DynStableName n = eqStableName m n+#else+ DynStableName m == DynStableName n = m == unsafeCoerce n+#endif makeDynStableName :: a -> IO DynStableName makeDynStableName a = do st <- makeStableName a- return $ DynStableName (unsafeCoerce st)+ return $ DynStableName st
data-reify.cabal view
@@ -1,46 +1,47 @@ Name: data-reify-Version: 0.6.1+Version: 0.6.2 Synopsis: Reify a recursive data structure into an explicit graph.-Description: 'data-reify' provided the ability to turn recursive structures into explicit graphs. - Many (implicitly or explicitly) recursive data structure can be given this ability, via- a type class instance. This gives an alternative to using 'Ref' for observable sharing.- .- Observable sharing in general is unsafe, so we use the IO monad to bound this effect,- but can be used safely even with 'unsafePerformIO' if some simple conditions are met.- Typically this package will be used to tie the knot with DSL's that depend of- observable sharing, like Lava.- .- Providing an instance for 'MuRef' is the mechanism for allowing a structure to be - reified into a graph, and several examples of this are provided.- .- History: - Version 0.1 used unsafe pointer compares.- Version 0.2 of 'data-reify' used 'StableName's, and was much faster.- Version 0.3 provided two versions of 'MuRef', the mono-typed version,- for trees of a single type,- and the dynamic-typed version, for trees of different types.- Version 0.4 used 'Int' as a synonym for 'Unique' rather than 'Data.Unique'- for node ids, by popular demand.- Version 0.5 merged the mono-typed and dynamic version again, by using - 'DynStableName', an unphantomized version of StableName.- .- © 2009 Andy Gill; BSD3 license.+Description: 'data-reify' provided the ability to turn recursive structures into explicit graphs.+ Many (implicitly or explicitly) recursive data structure can be given this ability, via+ a type class instance. This gives an alternative to using 'Ref' for observable sharing.+ .+ Observable sharing in general is unsafe, so we use the IO monad to bound this effect,+ but can be used safely even with 'unsafePerformIO' if some simple conditions are met.+ Typically this package will be used to tie the knot with DSL's that depend of+ observable sharing, like Lava.+ .+ Providing an instance for 'MuRef' is the mechanism for allowing a structure to be+ reified into a graph, and several examples of this are provided.+ .+ © 2009 Andy Gill; BSD3 license. -Category: Language, Data, Parsing, Reflection +Category: Language, Data, Parsing, Reflection License: BSD3 License-file: LICENSE Author: Andy Gill Maintainer: Andy Gill <andygill@ku.edu> Copyright: (c) 2009 Andy Gill-Homepage: http://www.ittc.ku.edu/csdl/fpg/Tools/IOReification+Homepage: http://ku-fpg.github.io/software/data-reify/ Stability: alpha build-type: Simple-Cabal-Version: >= 1.8+Cabal-Version: >= 1.10+tested-with: GHC == 7.0.4+ , GHC == 7.2.2+ , GHC == 7.4.2+ , GHC == 7.6.3+ , GHC == 7.8.4+ , GHC == 7.10.3+ , GHC == 8.0.2+ , GHC == 8.2.2+ , GHC == 8.4.4+ , GHC == 8.6.5+ , GHC == 8.8.3+ , GHC == 8.10.1 extra-source-files: CHANGELOG.md, README.md source-repository head type: git- location: git://github.com/ku-fpg/data-reify+ location: https://github.com/ku-fpg/data-reify Flag tests Description: Enable full development tree@@ -48,17 +49,21 @@ Library- Build-Depends: base >= 4 && < 5, containers+ Build-Depends: base >= 4 && < 5, hashable, containers, unordered-containers Exposed-modules: Data.Reify, Data.Reify.Graph Ghc-Options: -Wall+ if impl(ghc >= 8.6)+ ghc-options: -Wno-star-is-type+ default-language: Haskell2010 Executable data-reify-test1 Build-Depends: base, data-reify Main-Is: Test1.hs Hs-Source-Dirs: test ghc-options: -Wall+ default-language: Haskell2010 if !flag(tests) buildable: False @@ -68,6 +73,7 @@ Main-Is: Test2.hs Hs-Source-Dirs: test ghc-options: -Wall+ default-language: Haskell2010 if !flag(tests) buildable: False @@ -76,6 +82,7 @@ Main-Is: Test3.hs Hs-Source-Dirs: test ghc-options: -Wall+ default-language: Haskell2010 if !flag(tests) buildable: False @@ -84,6 +91,7 @@ Main-Is: Test4.hs Hs-Source-Dirs: test ghc-options: -Wall+ default-language: Haskell2010 if !flag(tests) buildable: False @@ -92,6 +100,7 @@ Main-Is: Test5.hs Hs-Source-Dirs: test ghc-options: -Wall+ default-language: Haskell2010 if !flag(tests) buildable: False @@ -100,6 +109,7 @@ Main-Is: Test6.hs Hs-Source-Dirs: test ghc-options: -Wall+ default-language: Haskell2010 if !flag(tests) buildable: False @@ -108,5 +118,6 @@ Main-Is: Test7.hs Hs-Source-Dirs: test ghc-options: -Wall+ default-language: Haskell2010 if !flag(tests) buildable: False
test/Test2.hs view
@@ -29,13 +29,14 @@ fmap f (StateDeRef a tr) = StateDeRef a [ (b,f s) | (b,s) <- tr ] main :: IO ()-main = reifyGraph s0 >>= print- +main = do reifyGraph s0 >>= print+ reifyGraphs [s0, s1] >>= print+ {- Alt: data State s i o = State s [(i,o,State s i o)] deriving Show- + state :: s -> State s i o state s = State s [] @@ -50,5 +51,5 @@ deriving Show -}- +