packages feed

rdf4h 3.0.0 → 3.0.1

raw patch · 22 files changed

+864/−902 lines, 22 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Data.RDF.Graph.HashMapS: data HashS
- Data.RDF.Graph.HashMapS: instance Control.DeepSeq.NFData (Data.RDF.Types.RDF Data.RDF.Graph.HashMapS.HashS)
- Data.RDF.Graph.HashMapS: instance Control.DeepSeq.NFData Data.RDF.Graph.HashMapS.HashS
- Data.RDF.Graph.HashMapS: instance Data.Binary.Class.Binary Data.RDF.Graph.HashMapS.HashS
- Data.RDF.Graph.HashMapS: instance Data.RDF.Types.Rdf Data.RDF.Graph.HashMapS.HashS
- Data.RDF.Graph.HashMapS: instance GHC.Generics.Generic (Data.RDF.Types.RDF Data.RDF.Graph.HashMapS.HashS)
- Data.RDF.Graph.HashMapS: instance GHC.Generics.Generic Data.RDF.Graph.HashMapS.HashS
- Data.RDF.Graph.HashMapSP: data HashSP
- Data.RDF.Graph.HashMapSP: instance Control.DeepSeq.NFData (Data.RDF.Types.RDF Data.RDF.Graph.HashMapSP.HashSP)
- Data.RDF.Graph.HashMapSP: instance Control.DeepSeq.NFData Data.RDF.Graph.HashMapSP.HashSP
- Data.RDF.Graph.HashMapSP: instance Data.Binary.Class.Binary Data.RDF.Graph.HashMapSP.HashSP
- Data.RDF.Graph.HashMapSP: instance Data.RDF.Types.Rdf Data.RDF.Graph.HashMapSP.HashSP
- Data.RDF.Graph.HashMapSP: instance GHC.Generics.Generic (Data.RDF.Types.RDF Data.RDF.Graph.HashMapSP.HashSP)
- Data.RDF.Graph.HashMapSP: instance GHC.Generics.Generic Data.RDF.Graph.HashMapSP.HashSP
- Data.RDF.Graph.MapSP: data SP
- Data.RDF.Graph.MapSP: instance Control.DeepSeq.NFData (Data.RDF.Types.RDF Data.RDF.Graph.MapSP.SP)
- Data.RDF.Graph.MapSP: instance Control.DeepSeq.NFData Data.RDF.Graph.MapSP.SP
- Data.RDF.Graph.MapSP: instance Data.Binary.Class.Binary Data.RDF.Graph.MapSP.SP
- Data.RDF.Graph.MapSP: instance Data.RDF.Types.Rdf Data.RDF.Graph.MapSP.SP
- Data.RDF.Graph.MapSP: instance GHC.Generics.Generic (Data.RDF.Types.RDF Data.RDF.Graph.MapSP.SP)
- Data.RDF.Graph.MapSP: instance GHC.Generics.Generic Data.RDF.Graph.MapSP.SP
+ Data.RDF: addTriple :: Rdf rdfImpl => RDF rdfImpl -> Triple -> RDF rdfImpl
+ Data.RDF: removeTriple :: Rdf rdfImpl => RDF rdfImpl -> Triple -> RDF rdfImpl
+ Data.RDF.Graph.AdjHashMap: data AdjHashMap
+ Data.RDF.Graph.AdjHashMap: instance Control.DeepSeq.NFData (Data.RDF.Types.RDF Data.RDF.Graph.AdjHashMap.AdjHashMap)
+ Data.RDF.Graph.AdjHashMap: instance Control.DeepSeq.NFData Data.RDF.Graph.AdjHashMap.AdjHashMap
+ Data.RDF.Graph.AdjHashMap: instance Data.Binary.Class.Binary Data.RDF.Graph.AdjHashMap.AdjHashMap
+ Data.RDF.Graph.AdjHashMap: instance Data.RDF.Types.Rdf Data.RDF.Graph.AdjHashMap.AdjHashMap
+ Data.RDF.Graph.AdjHashMap: instance GHC.Generics.Generic (Data.RDF.Types.RDF Data.RDF.Graph.AdjHashMap.AdjHashMap)
+ Data.RDF.Graph.AdjHashMap: instance GHC.Generics.Generic Data.RDF.Graph.AdjHashMap.AdjHashMap
+ Data.RDF.Query: uordered :: Triples -> Triples
+ Data.RDF.Types: addTriple :: Rdf rdfImpl => RDF rdfImpl -> Triple -> RDF rdfImpl
+ Data.RDF.Types: removeTriple :: Rdf rdfImpl => RDF rdfImpl -> Triple -> RDF rdfImpl

Files

bench/MainCriterion.hs view
@@ -3,6 +3,7 @@ module Main where  import Criterion+import Criterion.Types import Criterion.Main import Data.RDF import qualified Data.Text as T@@ -12,11 +13,24 @@ -- $ wget https://www.govtrack.us/data/rdf/bills.099.actions.rdf.gz -- $ gzip -d bills.099.actions.rdf.gz -parseXmlRDF :: Rdf a => String -> RDF a+parseXmlRDF :: Rdf a => T.Text -> RDF a parseXmlRDF s =-  let (Right rdf) = parseString (XmlParser Nothing Nothing) (T.pack s)+  let (Right rdf) = parseString (XmlParser Nothing Nothing) s   in rdf-  +{-# INLINE parseXmlRDF #-}++parseNtRDF :: Rdf a => T.Text -> RDF a+parseNtRDF s =+  let (Right rdf) = parseString NTriplesParser s+  in rdf+{-# INLINE parseNtRDF #-}++parseTtlRDF :: Rdf a => T.Text -> RDF a+parseTtlRDF s =+  let (Right rdf) = parseString (TurtleParser Nothing Nothing) s+  in rdf+{-# INLINE parseTtlRDF #-}+ queryGr :: Rdf a => (Maybe Node,Maybe Node,Maybe Node,RDF a) -> [Triple] queryGr (maybeS,maybeP,maybeO,rdf) = query rdf maybeS maybeP maybeO @@ -24,49 +38,58 @@ selectGr (selectorS,selectorP,selectorO,rdf) = select rdf selectorS selectorP selectorO  main :: IO ()-main = defaultMain [-   -- env (readFile "bills.102.rdf") $ \ ~(ttl_countries) ->-   -- bgroup "parse" [-   --   bench "HashS" $-   --     nf (parseXmlRDF  :: String -> RDF HashS) ttl_countries-   -- , bench "HashSP" $-   --     nf (parseXmlRDF  :: String -> RDF HashSP) ttl_countries-   -- , bench "SP" $-   --     nf (parseXmlRDF  :: String -> RDF SP) ttl_countries-   -- , bench "TList" $-   --     nf (parseXmlRDF  :: String -> RDF TList) ttl_countries-   -- , bench "TPatriciaTree" $-   --     nf (parseXmlRDF  :: String -> RDF TPatriciaTree) ttl_countries-   -- ]--   -- ,-   env (do ttl_countries <- readFile "bills.099.actions.rdf"-           let (Right rdf1) = parseString (XmlParser Nothing Nothing) (T.pack ttl_countries)-           let (Right rdf2) = parseString (XmlParser Nothing Nothing) (T.pack ttl_countries)-           let (Right rdf3) = parseString (XmlParser Nothing Nothing) (T.pack ttl_countries)-           let (Right rdf4) = parseString (XmlParser Nothing Nothing) (T.pack ttl_countries)-           return (rdf1 :: RDF TList,rdf2 :: RDF HashS,rdf3 :: RDF SP,rdf4::RDF HashSP) )-     $ \ ~(triplesList,hashMapS,mapSP,hashMapSP) ->-   bgroup "query"-     (queryBench "TList" triplesList-     ++ queryBench "HashS" hashMapS-     ++ queryBench "SP" mapSP-     ++ queryBench "HashSP" hashMapSP)+main =+  defaultMainWith+    (defaultConfig {resamples = 100})+    [ env+      -- fawltyContent <- T.pack <$> readFile "data/ttl/fawlty1.ttl"+        (do rdfContent <- T.pack <$> readFile "bills.099.actions.rdf"+            let (Right rdf1) =+                  parseString (XmlParser Nothing Nothing) rdfContent+            let (Right rdf2) =+                  parseString (XmlParser Nothing Nothing) rdfContent+            -- let (Right rdf3) =+            --       parseString (XmlParser Nothing Nothing) rdfContent+            -- let (Right rdf4) =+            --       parseString (XmlParser Nothing Nothing) rdfContent+            return+              ( rdf1 :: RDF TList+              , rdf2 :: RDF AdjHashMap+              )) $ \ ~(triplesList, adjMap) ->+        bgroup+          "rdf4h"+          --  bgroup+          --     "parsers"+          --     [ bench "AdjHashMap" $+          --       nf (parseTtlRDF :: T.Text -> RDF AdjHashMap) fawlty_towers+          --     , bench "HashSP" $+          --       nf (parseTtlRDF :: T.Text -> RDF HashSP) fawlty_towers+          --     , bench "SP" $ nf (parseTtlRDF :: T.Text -> RDF SP) fawlty_towers+          --     , bench "TList" $+          --       nf (parseTtlRDF :: T.Text -> RDF TList) fawlty_towers+          --     ]+          -- ,+          [ bgroup+              "query"+              (queryBench "TList" triplesList +++               queryBench "AdjHashMap" adjMap+               -- queryBench "SP" mapSP ++ queryBench "HashSP" hashMapSP+              )+          , bgroup+              "select"+              (selectBench "TList" triplesList +++               selectBench "AdjHashMap" adjMap+               -- selectBench "SP" mapSP ++ selectBench "HashSP" hashMapSP+              )+          , bgroup+            "count_triples"+            [ bench "TList" (nf (length . triplesOf) triplesList)+            , bench "AdjHashMap" (nf (length . triplesOf) adjMap)+            ]+          ]+    ] -   ,-   env (do ttl_countries <- readFile "bills.099.actions.rdf"-           let (Right rdf1) = parseString (XmlParser Nothing Nothing) (T.pack ttl_countries)-           let (Right rdf2) = parseString (XmlParser Nothing Nothing) (T.pack ttl_countries)-           let (Right rdf3) = parseString (XmlParser Nothing Nothing) (T.pack ttl_countries)-           let (Right rdf4) = parseString (XmlParser Nothing Nothing) (T.pack ttl_countries)-           return (rdf1 :: RDF TList,rdf2 :: RDF HashS,rdf3 :: RDF SP,rdf4 :: RDF HashSP) )-     $ \ ~(triplesList,hashMapS,mapSP,hashMapSP) ->-   bgroup "select"-     (selectBench "TList" triplesList-     ++ selectBench "HashS" hashMapS-     ++ selectBench "SP" mapSP-     ++ selectBench "HashSP" hashMapSP)- ]+          selectBench :: Rdf a => String -> RDF a -> [Benchmark] selectBench label gr =
rdf4h.cabal view
@@ -1,5 +1,5 @@ name:            rdf4h-version:         3.0.0+version:         3.0.1 synopsis:        A library for RDF processing in Haskell description:   'RDF for Haskell' is a library for working with RDF in Haskell.@@ -33,9 +33,9 @@                  , Data.RDF.Namespace                  , Data.RDF.Types                  , Data.RDF.Query-                 , Data.RDF.Graph.HashMapS-                 , Data.RDF.Graph.HashMapSP-                 , Data.RDF.Graph.MapSP+                 , Data.RDF.Graph.AdjHashMap+                 -- , Data.RDF.Graph.HashMapSP+                 -- , Data.RDF.Graph.MapSP                  -- this is very slow                  -- , Data.RDF.Graph.TPatriciaTree                  , Data.RDF.Graph.TList@@ -98,9 +98,9 @@   type:          exitcode-stdio-1.0   main-is:       Test.hs   other-modules: Data.RDF.GraphTestUtils-                 Data.RDF.Graph.HashS_Test-                 Data.RDF.Graph.HashSP_Test-                 Data.RDF.Graph.SP_Test+                 Data.RDF.Graph.AdjHashMap_Test+                 -- Data.RDF.Graph.HashSP_Test+                 -- Data.RDF.Graph.SP_Test                  -- Data.RDF.Graph.TriplesPatriciaTree_Test                  Data.RDF.Graph.TList_Test                  Text.RDF.RDF4H.TurtleParser_ConformanceTest
src/Data/RDF.hs view
@@ -13,9 +13,9 @@    -- * RDF type class instances   module Data.RDF.Graph.TList,-  module Data.RDF.Graph.HashMapS,-  module Data.RDF.Graph.HashMapSP,-  module Data.RDF.Graph.MapSP,+  module Data.RDF.Graph.AdjHashMap,+  -- module Data.RDF.Graph.HashMapSP,+  -- module Data.RDF.Graph.MapSP,    -- * RDF parsers and serializers   module Text.RDF.RDF4H.NTriplesSerializer,@@ -28,9 +28,9 @@  import Data.RDF.Namespace import Data.RDF.Graph.TList-import Data.RDF.Graph.HashMapS-import Data.RDF.Graph.HashMapSP-import Data.RDF.Graph.MapSP+import Data.RDF.Graph.AdjHashMap+-- import Data.RDF.Graph.HashMapSP+-- import Data.RDF.Graph.MapSP import Text.RDF.RDF4H.NTriplesSerializer import Text.RDF.RDF4H.TurtleSerializer import Text.RDF.RDF4H.NTriplesParser
+ src/Data/RDF/Graph/AdjHashMap.hs view
@@ -0,0 +1,317 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TupleSections, GeneralizedNewtypeDeriving #-}+{-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- |A graph implementation mapping hashed S to a mapping of+--  hashed P to hashed O, backed by 'Data.HashMap'.++module Data.RDF.Graph.AdjHashMap (AdjHashMap) where++import Prelude hiding (pred)+import Control.DeepSeq (NFData)+import Data.RDF.Types+import Data.RDF.Query+import Data.RDF.Namespace+import qualified Data.Map as Map+import Data.Hashable()+import Data.HashMap.Strict(HashMap)+import qualified Data.HashMap.Strict as HashMap+import Data.HashSet(HashSet)+import qualified Data.HashSet as Set+import Data.List+import GHC.Generics+import Data.Binary (Binary)++-- |A map-based graph implementation.+--+-- This instance of 'RDF' is an adjacency map with each subject+-- mapping to a mapping from a predicate node to to the adjacent nodes+-- via that predicate.+--+-- Given the following triples graph::+--+-- @+--   (http:\/\/example.com\/s1,http:\/\/example.com\/p1,http:\/\/example.com\/o1)+--   (http:\/\/example.com\/s1,http:\/\/example.com\/p1,http:\/\/example.com\/o2)+--   (http:\/\/example.com\/s1,http:\/\/example.com\/p2,http:\/\/example.com\/o1)+--   (http:\/\/example.com\/s2,http:\/\/example.com\/p3,http:\/\/example.com\/o3)+-- @+--+-- where+--+-- > hash "http://example.com/s1" = 1600134414+-- > hash "http://example.com/s2" = 1600134413+-- > hash "http://example.com/p1" = 1616912099+-- > hash "http://example.com/p2" = 1616912096+-- > hash "http://example.com/p3" = 1616912097+-- > hash "http://example.com/o1" = 1935686794+-- > hash "http://example.com/o2" = 1935686793+-- > hash "http://example.com/o3" = 1935686792+--+-- the in-memory hashmap representation of the triples graph is:+--+-- @+-- key:1600134414, value:(key:1616912099, value:[1935686794    -- (..\/s1,..\/p1,..\/o1)+--                                              ,1935686793];  -- (..\/s1,..\/p1,..\/o2)+--                        key:1616912096, value:[1935686794]); -- (..\/s1,..\/p2,..\/o1)+-- key:1600134413, value:(key:1616912097, value:[1935686792])  -- (..\/s1,..\/p3,..\/o3)+-- @+--+-- Worst-case time complexity of the graph functions, with respect+-- to the number of triples, are:+--+--  * 'empty'    : O(1)+--+--  * 'mkRdf'  : O(n)+--+--  * 'triplesOf': O(n)+--+--  * 'select'   : O(n)+--+--  * 'query'    : O(log n)+-- newtype HashS = HashS (TMaps, Maybe BaseUrl, PrefixMappings)+--                  deriving (NFData)++data AdjHashMap deriving (Generic)++instance Binary AdjHashMap+instance NFData AdjHashMap++data instance RDF AdjHashMap = AdjHashMap (TMaps, Maybe BaseUrl, PrefixMappings)+                 deriving (NFData,Generic)++instance Rdf AdjHashMap where+  baseUrl           = baseUrl'+  prefixMappings    = prefixMappings'+  addPrefixMappings = addPrefixMappings'+  empty             = empty'+  mkRdf             = mkRdf'+  triplesOf         = triplesOf'+  uniqTriplesOf     = uniqTriplesOf'+  select            = select'+  query             = query'+  showGraph         = showGraph'+  addTriple         = addTriple'+  removeTriple      = removeTriple'++-- instance Show (AdjHashMap) where+--   show (AdjHashMap ((spoMap, _), _, _)) =+--     let ts = concatMap (uncurry tripsSubj) subjPredMaps+--           where subjPredMaps = HashMap.toList spoMap+--     in concatMap (\t -> show t ++ "\n") ts++showGraph' :: RDF AdjHashMap -> [Char]+showGraph' ((AdjHashMap ((spoMap, _), _, _))) =+    let ts = concatMap (uncurry tripsSubj) subjPredMaps+          where subjPredMaps = HashMap.toList spoMap+    in concatMap (\t -> show t ++ "\n") ts++-- instance Show (RDF AdjHashMap) where+--   show gr = concatMap (\t -> show t ++ "\n")  (triplesOf gr)++-- some convenience type alias for readability++-- An adjacency map for a subject, mapping from a predicate node to+-- to the adjacent nodes via that predicate.+type AdjacencyMap = HashMap Predicate (HashSet Node)++type Adjacencies = HashSet Node++type TMap   = HashMap Node AdjacencyMap+type TMaps  = (TMap, TMap)+++baseUrl' :: RDF AdjHashMap -> Maybe BaseUrl+baseUrl' (AdjHashMap (_, baseURL, _)) = baseURL++prefixMappings' :: RDF AdjHashMap -> PrefixMappings+prefixMappings' (AdjHashMap (_, _, pms)) = pms++addPrefixMappings' :: RDF AdjHashMap -> PrefixMappings -> Bool -> RDF AdjHashMap+addPrefixMappings' (AdjHashMap (ts, baseURL, pms)) pms' replace = +  let merge = if replace then flip mergePrefixMappings else mergePrefixMappings+  in  AdjHashMap (ts, baseURL, merge pms pms')++empty' :: RDF AdjHashMap+empty' = AdjHashMap ((HashMap.empty, HashMap.empty), Nothing, PrefixMappings Map.empty)++mkRdf' :: Triples -> Maybe BaseUrl -> PrefixMappings -> RDF AdjHashMap+mkRdf' ts baseURL pms = AdjHashMap (mergeTs (HashMap.empty, HashMap.empty) ts, baseURL, pms)++addTriple' :: RDF AdjHashMap -> Triple -> RDF AdjHashMap+addTriple' (AdjHashMap (tmaps, baseURL, pms)) t =+  let newTMaps = mergeTs tmaps [t]+  in AdjHashMap (newTMaps, baseURL, pms)++removeTriple' :: RDF AdjHashMap -> Triple -> RDF AdjHashMap+removeTriple' (AdjHashMap ((spoMap, opsMap), baseURL, pms)) (Triple s p o) =+  (AdjHashMap (new_tmaps, baseURL, pms))+  where+    new_tmaps = (newSpoMap, newOpsMap)+    newSpoMap =+      case HashMap.lookup s spoMap of+        Nothing -> spoMap+        Just poAdjMap ->+          case HashMap.lookup p poAdjMap of+            Nothing -> spoMap+            Just oHashSet ->+              if not (Set.member o oHashSet)+                then spoMap+                else let newPoAdjMap =+                           HashMap.adjust+                             (\oHashSet' -> Set.delete o oHashSet')+                             p+                             poAdjMap+                     in HashMap.adjust (\_poAdjMap' -> newPoAdjMap) s spoMap+    newOpsMap =+      case HashMap.lookup o opsMap of+        Nothing -> opsMap+        Just poAdjMap ->+          case HashMap.lookup p poAdjMap of+            Nothing -> opsMap+            Just sHashSet ->+              if not (Set.member s sHashSet)+                then opsMap+                else let newPoAdjMap =+                           HashMap.adjust+                             (\sHashSet' -> Set.delete s sHashSet')+                             p+                             poAdjMap+                     in HashMap.adjust (\_poAdjMap' -> newPoAdjMap) o opsMap      ++mergeTs :: TMaps -> [Triple] -> TMaps+mergeTs = foldl' mergeT+  where+    mergeT :: TMaps -> Triple -> TMaps+    mergeT m t = mergeT' m (subjectOf t) (predicateOf t) (objectOf t)++mergeT' :: TMaps -> Subject -> Predicate -> Object -> TMaps+mergeT' (spo, ops) s p o = (mergeT'' spo s p o, mergeT'' ops o p s)++mergeT'' :: TMap -> Subject -> Predicate -> Object -> TMap+mergeT'' m s p o =+  if s `HashMap.member` m then+    (if p `HashMap.member` adjs then HashMap.insert s addPredObj m+       else HashMap.insert s addNewPredObjMap m)+    else HashMap.insert s newPredMap m+  where+    adjs = HashMap.lookupDefault HashMap.empty s m+    newPredMap :: HashMap Predicate (HashSet Object)+    newPredMap = HashMap.singleton p (Set.singleton o)+    addNewPredObjMap :: HashMap Predicate (HashSet Object)+    addNewPredObjMap = HashMap.insert p (Set.singleton o) adjs+    addPredObj :: HashMap Predicate (HashSet Object)+    addPredObj = HashMap.insert p (Set.insert o (get p adjs)) adjs+    --get :: (Ord k, Hashable k) => k -> HashMap k v -> v+    get = HashMap.lookupDefault Set.empty++-- 3 following functions support triplesOf+triplesOf' :: RDF AdjHashMap -> Triples+triplesOf' (AdjHashMap ((spoMap, _), _, _)) = concatMap (uncurry tripsSubj) subjPredMaps+  where subjPredMaps = HashMap.toList spoMap++-- naive implementation for now+uniqTriplesOf' :: RDF AdjHashMap -> Triples+uniqTriplesOf' = nub . expandTriples++tripsSubj :: Subject -> AdjacencyMap -> Triples+tripsSubj s adjMap = concatMap (uncurry (tfsp s)) (HashMap.toList adjMap)+  where tfsp = tripsForSubjPred++tripsForSubjPred :: Subject -> Predicate -> Adjacencies -> Triples+tripsForSubjPred s p adjs = map (Triple s p) (Set.toList adjs)++-- supports select+select' :: RDF AdjHashMap -> NodeSelector -> NodeSelector -> NodeSelector -> Triples+select' (AdjHashMap ((spoMap,_),_,_)) subjFn predFn objFn =+  map (\(s,p,o) -> Triple s p o) $ Set.toList $ sel1 subjFn predFn objFn spoMap++sel1 :: NodeSelector -> NodeSelector -> NodeSelector -> TMap -> HashSet (Node, Node, Node)+sel1 (Just subjFn) p o spoMap =+  Set.unions $ map (sel2 p o) $ filter (\(x,_) -> subjFn x) $ HashMap.toList spoMap+sel1 Nothing p o spoMap = Set.unions $ map (sel2 p o) $ HashMap.toList spoMap++sel2 :: NodeSelector -> NodeSelector -> (Node, HashMap Node (HashSet Node)) -> HashSet (Node, Node, Node)+sel2 (Just predFn) mobjFn (s, ps) =+  Set.map (\(p,o) -> (s,p,o)) $+  foldl' Set.union Set.empty $+  map (sel3 mobjFn) poMapS :: HashSet (Node, Node, Node)+  where+    poMapS :: [(Node, HashSet Node)]+    poMapS = filter (\(k,_) -> predFn k) $ HashMap.toList ps+sel2 Nothing mobjFn (s, ps) =+  Set.map (\(p,o) -> (s,p,o)) $+  foldl' Set.union Set.empty $+  map (sel3 mobjFn) poMaps+  where+    poMaps = HashMap.toList ps++sel3 :: NodeSelector -> (Node, HashSet Node) -> HashSet (Node, Node)+sel3 (Just objFn) (p, os) = Set.map (\o -> (p, o)) $ Set.filter objFn os+sel3 Nothing      (p, os) = Set.map (\o -> (p, o)) os++-- support query+query' :: RDF AdjHashMap -> Maybe Subject -> Maybe Predicate -> Maybe Object -> Triples+query' (AdjHashMap (m,_ , _)) subj pred obj = map (\(s, p, o) -> Triple s p o) $ Set.toList (q1 subj pred obj m)++q1 :: Maybe Node -> Maybe Node -> Maybe Node -> TMaps -> HashSet (Node, Node, Node)+q1 (Just s) p o        (spoMap, _     ) = q2 p o (s, HashMap.lookupDefault HashMap.empty s spoMap)+q1 s        p (Just o) (_     , opsMap) = Set.map (\(o',p',s') -> (s',p',o')) $ q2 p s (o, HashMap.lookupDefault HashMap.empty o opsMap)+q1 Nothing (Just p) Nothing (spoMap,_) =+  let (filtered::HashMap Node (HashMap Node (HashSet Node)))+        = HashMap.filter (\poAdjMap -> HashMap.member p poAdjMap) spoMap+      subjXS = HashMap.toList filtered :: [(Node,AdjacencyMap)]+      ys = concatMap (\(s,poMap) ->+                        let objs = map snd (HashMap.toList poMap :: [(Predicate,HashSet Node)])+                        in concatMap (\objHash -> map (\o -> (s,p,o)) (Set.toList objHash)) objs+                     ) subjXS+  in Set.fromList ys+{-+      (xs::[(Subject,Predicate,Object)]) = HashMap.foldlWithKey' f [] filtered+      f triples s poAdjMap =+        let objs = HashMap.elems poAdjMap+        in triples ++ concatMap (\oSet -> map (\o -> (s,p,o)) (Set.toList oSet)) objs+  in Set.fromList xs+-}++q1 Nothing  p o        (spoMap, _     ) =+  let hashSets = map (q2 p o) (HashMap.toList spoMap) :: [HashSet (Node,Node,Node)]+  in Set.unions hashSets++-- | takes a @Maybe Predicate@ and a @Maybe Object@, a subject and+-- predicate map tuple, and returns a (s,p,o) hash set.+q2+  :: Maybe Node+  -> Maybe Node+  -> (Node, HashMap Node (HashSet Node))+  -> HashSet (Node, Node, Node)+q2 (Just p) o (s, pmap) =+  let objAdjHashMapetMaybe = HashMap.lookup p pmap :: Maybe (HashSet Node) -- lookup object hash set+  in case objAdjHashMapetMaybe of+       Nothing -> Set.empty+       Just objAdjHashMapet ->+         let poAdjHashMapet = q3 o (p,objAdjHashMapet)+         in Set.map (\(p', o') -> (s, p', o')) poAdjHashMapet+q2 Nothing o (s, pmap) =+  Set.map (\(x, y) -> (s, x, y)) $ Set.unions $ map (q3 o) opmaps+  where+    opmaps :: [(Node, HashSet Node)]+    opmaps = HashMap.toList pmap++-- | looks up an object in an object hash set. If it exists, then this+-- function returns a hashset with a set with single (p,o) tuple+-- element. If the @Maybe Object@ value is @Empty@, then create a hash+-- set of (p,o) tuples for every object in the object hash set.+q3 :: Maybe Node -- ^ object+   -> (Node, HashSet Node) -- ^ predicate and object hash set tuple+   -> HashSet (Node, Node) -- ^ hash set of (p,o) tuples+q3 (Just o) (p, os) =+  if o `Set.member` os -- if the queried object is in the object set+    then Set.singleton (p, o) -- return a set with a single (p,o) tuple element +    else Set.empty -- otherwise return an empty set+q3 Nothing (p, os) = Set.map (\o -> (p, o)) os
− src/Data/RDF/Graph/HashMapS.hs
@@ -1,233 +0,0 @@-{-# LANGUAGE DeriveAnyClass #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TupleSections, GeneralizedNewtypeDeriving #-}-{-# LANGUAGE EmptyDataDecls #-}---- |A graph implementation mapping hashed S to a mapping of---  hashed P to hashed O, backed by 'Data.HashMap'.--module Data.RDF.Graph.HashMapS (HashS) where--import Prelude hiding (pred)-import Control.DeepSeq (NFData)-import Data.RDF.Types-import Data.RDF.Query-import Data.RDF.Namespace-import qualified Data.Map as Map-import Data.Hashable()-import Data.HashMap.Strict(HashMap)-import qualified Data.HashMap.Strict as HashMap-import Data.HashSet(HashSet)-import qualified Data.HashSet as Set-import Data.List-import GHC.Generics-import Data.Binary (Binary)---- |A map-based graph implementation.------ This instance of 'RDF' is an adjacency map with each subject--- mapping to a mapping from a predicate node to to the adjacent nodes--- via that predicate.------ Given the following triples graph::------ @---   (http:\/\/example.com\/s1,http:\/\/example.com\/p1,http:\/\/example.com\/o1)---   (http:\/\/example.com\/s1,http:\/\/example.com\/p1,http:\/\/example.com\/o2)---   (http:\/\/example.com\/s1,http:\/\/example.com\/p2,http:\/\/example.com\/o1)---   (http:\/\/example.com\/s2,http:\/\/example.com\/p3,http:\/\/example.com\/o3)--- @------ where------ > hash "http://example.com/s1" = 1600134414--- > hash "http://example.com/s2" = 1600134413--- > hash "http://example.com/p1" = 1616912099--- > hash "http://example.com/p2" = 1616912096--- > hash "http://example.com/p3" = 1616912097--- > hash "http://example.com/o1" = 1935686794--- > hash "http://example.com/o2" = 1935686793--- > hash "http://example.com/o3" = 1935686792------ the in-memory hashmap representation of the triples graph is:------ @--- key:1600134414, value:(key:1616912099, value:[1935686794    -- (..\/s1,..\/p1,..\/o1)---                                              ,1935686793];  -- (..\/s1,..\/p1,..\/o2)---                        key:1616912096, value:[1935686794]); -- (..\/s1,..\/p2,..\/o1)--- key:1600134413, value:(key:1616912097, value:[1935686792])  -- (..\/s1,..\/p3,..\/o3)--- @------ Worst-case time complexity of the graph functions, with respect--- to the number of triples, are:------  * 'empty'    : O(1)------  * 'mkRdf'  : O(n)------  * 'triplesOf': O(n)------  * 'select'   : O(n)------  * 'query'    : O(log n)--- newtype HashS = HashS (TMaps, Maybe BaseUrl, PrefixMappings)---                  deriving (NFData)--data HashS deriving (Generic)--instance Binary HashS-instance NFData HashS--data instance RDF HashS = HashS (TMaps, Maybe BaseUrl, PrefixMappings)-                 deriving (NFData,Generic)--instance Rdf HashS where-  baseUrl           = baseUrl'-  prefixMappings    = prefixMappings'-  addPrefixMappings = addPrefixMappings'-  empty             = empty'-  mkRdf             = mkRdf'-  triplesOf         = triplesOf'-  uniqTriplesOf     = uniqTriplesOf'-  select            = select'-  query             = query'-  showGraph         = showGraph'---- instance Show (HashS) where---   show (HashS ((spoMap, _), _, _)) =---     let ts = concatMap (uncurry tripsSubj) subjPredMaps---           where subjPredMaps = HashMap.toList spoMap---     in concatMap (\t -> show t ++ "\n") ts--showGraph' :: RDF HashS -> [Char]-showGraph' ((HashS ((spoMap, _), _, _))) =-    let ts = concatMap (uncurry tripsSubj) subjPredMaps-          where subjPredMaps = HashMap.toList spoMap-    in concatMap (\t -> show t ++ "\n") ts---- instance Show (RDF HashS) where---   show gr = concatMap (\t -> show t ++ "\n")  (triplesOf gr)---- some convenience type alias for readability---- An adjacency map for a subject, mapping from a predicate node to--- to the adjacent nodes via that predicate.-type AdjacencyMap = HashMap Predicate (HashSet Node)--type Adjacencies = HashSet Node--type TMap   = HashMap Node AdjacencyMap-type TMaps  = (TMap, TMap)---baseUrl' :: RDF HashS -> Maybe BaseUrl-baseUrl' (HashS (_, baseURL, _)) = baseURL--prefixMappings' :: RDF HashS -> PrefixMappings-prefixMappings' (HashS (_, _, pms)) = pms--addPrefixMappings' :: RDF HashS -> PrefixMappings -> Bool -> RDF HashS-addPrefixMappings' (HashS (ts, baseURL, pms)) pms' replace = -  let merge = if replace then flip mergePrefixMappings else mergePrefixMappings-  in  HashS (ts, baseURL, merge pms pms')--empty' :: RDF HashS-empty' = HashS ((HashMap.empty, HashMap.empty), Nothing, PrefixMappings Map.empty)--mkRdf' :: Triples -> Maybe BaseUrl -> PrefixMappings -> RDF HashS-mkRdf' ts baseURL pms = HashS (mergeTs (HashMap.empty, HashMap.empty) ts, baseURL, pms)--mergeTs :: TMaps -> [Triple] -> TMaps-mergeTs = foldl' mergeT-  where-    mergeT :: TMaps -> Triple -> TMaps-    mergeT m t = mergeT' m (subjectOf t) (predicateOf t) (objectOf t)--mergeT' :: TMaps -> Subject -> Predicate -> Object -> TMaps-mergeT' (spo, ops) s p o = (mergeT'' spo s p o, mergeT'' ops o p s)--mergeT'' :: TMap -> Subject -> Predicate -> Object -> TMap-mergeT'' m s p o =-  if s `HashMap.member` m then-    (if p `HashMap.member` adjs then HashMap.insert s addPredObj m-       else HashMap.insert s addNewPredObjMap m)-    else HashMap.insert s newPredMap m-  where-    adjs = HashMap.lookupDefault HashMap.empty s m-    newPredMap :: HashMap Predicate (HashSet Object)-    newPredMap = HashMap.singleton p (Set.singleton o)-    addNewPredObjMap :: HashMap Predicate (HashSet Object)-    addNewPredObjMap = HashMap.insert p (Set.singleton o) adjs-    addPredObj :: HashMap Predicate (HashSet Object)-    addPredObj = HashMap.insert p (Set.insert o (get p adjs)) adjs-    --get :: (Ord k, Hashable k) => k -> HashMap k v -> v-    get = HashMap.lookupDefault Set.empty---- 3 following functions support triplesOf-triplesOf' :: RDF HashS -> Triples-triplesOf' (HashS ((spoMap, _), _, _)) = concatMap (uncurry tripsSubj) subjPredMaps-  where subjPredMaps = HashMap.toList spoMap---- naive implementation for now-uniqTriplesOf' :: RDF HashS -> Triples-uniqTriplesOf' = nub . expandTriples--tripsSubj :: Subject -> AdjacencyMap -> Triples-tripsSubj s adjMap = concatMap (uncurry (tfsp s)) (HashMap.toList adjMap)-  where tfsp = tripsForSubjPred--tripsForSubjPred :: Subject -> Predicate -> Adjacencies -> Triples-tripsForSubjPred s p adjs = map (Triple s p) (Set.toList adjs)---- supports select-select' :: RDF HashS -> NodeSelector -> NodeSelector -> NodeSelector -> Triples-select' (HashS ((spoMap,_),_,_)) subjFn predFn objFn =-  map (\(s,p,o) -> Triple s p o) $ Set.toList $ sel1 subjFn predFn objFn spoMap--sel1 :: NodeSelector -> NodeSelector -> NodeSelector -> TMap -> HashSet (Node, Node, Node)-sel1 (Just subjFn) p o spoMap =-  Set.unions $ map (sel2 p o) $ filter (\(x,_) -> subjFn x) $ HashMap.toList spoMap-sel1 Nothing p o spoMap = Set.unions $ map (sel2 p o) $ HashMap.toList spoMap--sel2 :: NodeSelector -> NodeSelector -> (Node, HashMap Node (HashSet Node)) -> HashSet (Node, Node, Node)-sel2 (Just predFn) mobjFn (s, ps) =-  Set.map (\(p,o) -> (s,p,o)) $-  foldl' Set.union Set.empty $-  map (sel3 mobjFn) poMapS :: HashSet (Node, Node, Node)-  where-    poMapS :: [(Node, HashSet Node)]-    poMapS = filter (\(k,_) -> predFn k) $ HashMap.toList ps-sel2 Nothing mobjFn (s, ps) =-  Set.map (\(p,o) -> (s,p,o)) $-  foldl' Set.union Set.empty $-  map (sel3 mobjFn) poMaps-  where-    poMaps = HashMap.toList ps--sel3 :: NodeSelector -> (Node, HashSet Node) -> HashSet (Node, Node)-sel3 (Just objFn) (p, os) = Set.map (\o -> (p, o)) $ Set.filter objFn os-sel3 Nothing      (p, os) = Set.map (\o -> (p, o)) os---- support query-query' :: RDF HashS -> Maybe Subject -> Maybe Predicate -> Maybe Object -> Triples-query' (HashS (m,_ , _)) subj pred obj = map f $ Set.toList $ q1 subj pred obj m-  where f (s, p, o) = Triple s p o--q1 :: Maybe Node -> Maybe Node -> Maybe Node -> TMaps -> HashSet (Node, Node, Node)-q1 (Just s) p o        (spoMap, _     ) = q2 p o (s, HashMap.lookupDefault HashMap.empty s spoMap)-q1 s        p (Just o) (_     , opsMap) = Set.map (\(o',p',s') -> (s',p',o')) $ q2 p s (o, HashMap.lookupDefault HashMap.empty o opsMap)-q1 Nothing  p o        (spoMap, _     ) = Set.unions $ map (q2 p o) $ HashMap.toList spoMap--q2 :: Maybe Node -> Maybe Node -> (Node, HashMap Node (HashSet Node)) -> HashSet (Node, Node, Node)-q2 (Just p) o (s, pmap) =-  maybe Set.empty (Set.map (\ (p', o') -> (s, p', o')) . q3 o . (p,)) $ HashMap.lookup p pmap-q2 Nothing o (s, pmap) = Set.map (\(x,y) -> (s,x,y)) $ Set.unions $ map (q3 o) opmaps-  where opmaps ::[(Node, HashSet Node)]-        opmaps = HashMap.toList pmap--q3 :: Maybe Node -> (Node, HashSet Node) -> HashSet (Node, Node)-q3 (Just o) (p, os) = if o `Set.member` os then Set.singleton (p, o) else Set.empty-q3 Nothing  (p, os) = Set.map (\o -> (p, o)) os
− src/Data/RDF/Graph/HashMapSP.hs
@@ -1,185 +0,0 @@-{-# LANGUAGE DeriveAnyClass #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TupleSections, GeneralizedNewtypeDeriving #-}-{-# LANGUAGE EmptyDataDecls #-}---- |A graph implementation mapping (S,P) pairs to O, backed by 'Data.Map'.--module Data.RDF.Graph.HashMapSP (HashSP) where--import Prelude hiding (pred)-import Control.DeepSeq (NFData)-import Data.RDF.Types-import Data.RDF.Query-import Data.RDF.Namespace-import Data.HashMap.Strict (HashMap)-import qualified Data.HashMap.Strict as HashMap-import qualified Data.Map as Map-import Data.List-import GHC.Generics-import Data.Binary (Binary)--data HashSP deriving (Generic)--instance Binary HashSP-instance NFData HashSP---- |A map-based graph implementation.--data instance RDF HashSP = HashSP (SPMap, Maybe BaseUrl, PrefixMappings)-                 deriving (NFData,Generic)--instance Rdf HashSP where-  baseUrl           = baseUrl'-  prefixMappings    = prefixMappings'-  addPrefixMappings = addPrefixMappings'-  empty             = empty'-  mkRdf             = mkRdf'-  triplesOf         = triplesOf'-  uniqTriplesOf     = uniqTriplesOf'-  select            = select'-  query             = query'-  showGraph         = showGraph'---- instance Show (HashSP) where---   show (HashSP (tsMap,_,_)) =---     let ts = (concatMap (\((s,p),oList) -> map (Triple s p) oList) . HashMap.toList) tsMap---     in concatMap (\t -> show t ++ "\n") ts--showGraph' :: RDF HashSP -> [Char]-showGraph' (HashSP (tsMap,_,_)) =-  let ts = (concatMap (\((s,p),oList) -> map (Triple s p) oList) . HashMap.toList) tsMap-  in concatMap (\t -> show t ++ "\n") ts-  --- instance Show (HashSP) where---   show gr = concatMap (\t -> show t ++ "\n")  (triplesOf gr)--type SPMap = HashMap (Subject,Predicate) [Object]--baseUrl' :: RDF HashSP -> Maybe BaseUrl-baseUrl' (HashSP (_, baseURL, _)) = baseURL--prefixMappings' :: RDF HashSP -> PrefixMappings-prefixMappings' (HashSP (_, _, pms)) = pms--addPrefixMappings' :: RDF HashSP -> PrefixMappings -> Bool -> RDF HashSP-addPrefixMappings' (HashSP (tsMap, baseURL, pms)) pms' replace =-  let merge = if replace then flip mergePrefixMappings else mergePrefixMappings-  in  HashSP (tsMap, baseURL, merge pms pms')--empty' :: RDF HashSP-empty' = HashSP (HashMap.empty, Nothing, PrefixMappings Map.empty)--mkRdf' :: Triples -> Maybe BaseUrl -> PrefixMappings -> RDF HashSP-mkRdf' triples baseURL pms = HashSP (tsMap, baseURL, pms)-    where-      tsMap = sortAndGroup triples-      sortAndGroup xs = HashMap.fromListWith (++) [((s,p), [o]) | Triple s p o <- xs]--triplesOf' :: RDF HashSP -> Triples-triplesOf' (HashSP (tsMap,_,_)) = (concatMap (\((s,p),oList) -> map (Triple s p) oList) . HashMap.toList) tsMap--uniqTriplesOf' :: RDF HashSP -> Triples-uniqTriplesOf' = nub . expandTriples--select' :: RDF HashSP -> NodeSelector -> NodeSelector -> NodeSelector -> Triples-select' gr Nothing Nothing Nothing =-    triplesOf' gr--select' (HashSP (tsMap,_,_))    Nothing  (Just pSelector) Nothing  =-    HashMap.foldrWithKey findTripleWithP [] tsMap-    where-      findTripleWithP (s,p) oList ts = if pSelector p-                                       then map (Triple s p) oList ++ ts-                                       else ts--select' (HashSP (tsMap,_,_))    Nothing  Nothing  (Just oSelector) =-    HashMap.foldrWithKey findTripleWithS [] tsMap-    where-      findTripleWithS (s,p) oList ts = map (Triple s p) (filter oSelector oList) ++ ts--select' (HashSP (tsMap,_,_))    Nothing  (Just pSelector) (Just oSelector) =-    HashMap.foldrWithKey findTripleWithS [] tsMap-    where-      findTripleWithS (s,p) oList ts = if pSelector p-                                       then map (Triple s p) (filter oSelector oList) ++ ts-                                       else ts--select' (HashSP (tsMap,_,_))    (Just sSelector) Nothing  Nothing  =-    HashMap.foldrWithKey findTripleWithS [] tsMap-    where-      findTripleWithS (s,p) oList ts = if sSelector s-                                       then map (Triple s p) oList ++ ts-                                       else ts--select' (HashSP (tsMap,_,_))    (Just sSelector) (Just pSelector) Nothing =-    HashMap.foldrWithKey findTripleWithS [] tsMap-    where-      findTripleWithS (s,p) oList ts = if sSelector s && pSelector p-                                       then map (Triple s p) oList ++ ts-                                       else ts--select' (HashSP (tsMap,_,_))    (Just sSelector) Nothing  (Just oSelector) =-    HashMap.foldrWithKey findTripleWithS [] tsMap-    where-      findTripleWithS (s,p) oList ts = if sSelector s-                                        then map (Triple s p) (filter oSelector oList) ++ ts-                                        else ts--select' (HashSP (tsMap,_,_))    (Just sSelector) (Just pSelector) (Just oSelector) =-    HashMap.foldrWithKey findTripleWithS [] tsMap-    where-      findTripleWithS (s,p) oList ts = if sSelector s && pSelector p-                                       then map (Triple s p) (filter oSelector oList) ++ ts-                                       else ts--query' :: RDF HashSP -> Maybe Subject -> Maybe Predicate -> Maybe Object -> Triples-query' gr Nothing  Nothing  Nothing  =-    triplesOf' gr--query' (HashSP (tsMap,_,_))    Nothing  (Just p) Nothing  =-    HashMap.foldrWithKey findTripleWithP [] tsMap-    where-      findTripleWithP (s,p') oList ts = if p == p'-                                        then map (Triple s p) oList ++ ts-                                        else ts--query' (HashSP (tsMap,_,_))    Nothing  Nothing  (Just o) =-    HashMap.foldrWithKey findTripleWithS [] tsMap-    where-      findTripleWithS (s,p) oList ts = map (Triple s p) (filter (== o) oList) ++ ts--query' (HashSP (tsMap,_,_))    Nothing  (Just p) (Just o) =-    HashMap.foldrWithKey findTripleWithS [] tsMap-    where-      findTripleWithS (s,p') oList ts = if p == p'-                                        then map (Triple s p) (filter (== o) oList) ++ ts-                                        else ts--query' (HashSP (tsMap,_,_))    (Just s) Nothing  Nothing  =-    HashMap.foldrWithKey findTripleWithS [] tsMap-    where-      findTripleWithS (s',p) oList ts = if s == s'-                                        then map (Triple s p) oList ++ ts-                                        else ts---- optimal pattern for this RDF HashSP instance-query' (HashSP (tsMap,_,_))    (Just s) (Just p) Nothing =-    (map (Triple s p) . HashMap.lookupDefault [] (s,p)) tsMap--query' (HashSP (tsMap,_,_))    (Just s) Nothing  (Just o) =-    HashMap.foldrWithKey findTripleWithS [] tsMap-    where-      findTripleWithS (s',p) oList ts = if s == s'-                                        then map (Triple s p) (filter (== o) oList) ++ ts-                                        else ts--query' (HashSP (tsMap,_,_))    (Just s) (Just p) (Just o) =-    HashMap.foldrWithKey findTripleWithS [] tsMap-    where-      findTripleWithS (s',p') oList ts = if s == s' && p == p'-                                        then map (Triple s p) (filter (== o) oList) ++ ts-                                        else ts
− src/Data/RDF/Graph/MapSP.hs
@@ -1,208 +0,0 @@-{-# LANGUAGE DeriveAnyClass #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE EmptyDataDecls #-}----- |A graph implementation mapping (S,P) pairs to O, backed by 'Data.Map'.--module Data.RDF.Graph.MapSP (SP) where--import Prelude hiding (pred)-import Control.DeepSeq (NFData)-import Data.RDF.Types-import Data.RDF.Query-import Data.RDF.Namespace-import Data.Map (Map)-import qualified Data.Map as Map-import Data.List-import GHC.Generics-import Data.Binary (Binary)---- |A map-based graph implementation.------ This instance of 'RDF' is an adjacency map with each subject--- mapping to a mapping from a predicate node to to the adjacent nodes--- via that predicate.------ Given the following triples graph::------ @---   (http:\/\/example.com\/s1,http:\/\/example.com\/p1,http:\/\/example.com\/o1)---   (http:\/\/example.com\/s1,http:\/\/example.com\/p1,http:\/\/example.com\/o2)---   (http:\/\/example.com\/s1,http:\/\/example.com\/p2,http:\/\/example.com\/o1)---   (http:\/\/example.com\/s2,http:\/\/example.com\/p3,http:\/\/example.com\/o3)--- @------ the in-memory map representation of the triples graph is:------ @--- key:(http:\/\/example.com\/s1,http:\/\/example.com\/p1),--- value:[http:\/\/example.com\/o1,http:\/\/example.com\/o2];------ key:(http:\/\/example.com\/s1,http:\/\/example.com\/p2),--- value:[http:\/\/example.com\/o1];------ key:(http:\/\/example.com\/s2,http:\/\/example.com\/p3),--- value:[http:\/\/example.com\/o3];--- @--data SP deriving (Generic)-instance Binary SP-instance NFData SP--data instance RDF SP = SP (SPMap, Maybe BaseUrl, PrefixMappings)-                     deriving (Generic,NFData)--instance Rdf SP where-  baseUrl           = baseUrl'-  prefixMappings    = prefixMappings'-  addPrefixMappings = addPrefixMappings'-  empty             = empty'-  mkRdf             = mkRdf'-  triplesOf         = triplesOf'-  uniqTriplesOf     = uniqTriplesOf'-  select            = select'-  query             = query'-  showGraph         = showGraph'---- instance Show SP where---   show (SP (tsMap,_,_)) =---     let ts = (concatMap (\((s,p),oList) -> map (Triple s p) oList) . Map.toList) tsMap---     in concatMap (\t -> show t ++ "\n") ts--showGraph' :: RDF SP -> String-showGraph' (SP (tsMap,_,_)) =-  let ts = (concatMap (\((s,p),oList) -> map (Triple s p) oList) . Map.toList) tsMap-    in concatMap (\t -> show t ++ "\n") ts--type SPMap = Map (Subject,Predicate) [Object]--baseUrl' :: RDF SP -> Maybe BaseUrl-baseUrl' (SP (_, baseURL, _)) = baseURL--prefixMappings' :: RDF SP -> PrefixMappings-prefixMappings' (SP (_, _, pms)) = pms--addPrefixMappings' :: RDF SP -> PrefixMappings -> Bool -> RDF SP-addPrefixMappings' (SP (tsMap, baseURL, pms)) pms' replace =-  let merge = if replace then flip mergePrefixMappings else mergePrefixMappings-  in  SP (tsMap, baseURL, merge pms pms')--empty' :: RDF SP-empty' = SP (Map.empty, Nothing, PrefixMappings Map.empty)--mkRdf' :: Triples -> Maybe BaseUrl -> PrefixMappings -> RDF SP-mkRdf' triples baseURL pms = SP (tsMap, baseURL, pms)-    where-      tsMap = sortAndGroup triples-      sortAndGroup xs = Map.fromListWith (++) [((s,p), [o]) | Triple s p o <- xs]--triplesOf' :: RDF SP -> Triples-triplesOf' (SP (tsMap,_,_)) = (concatMap (\((s,p),oList) -> map (Triple s p) oList) . Map.toList) tsMap--uniqTriplesOf' :: RDF SP -> Triples-uniqTriplesOf' = nub . expandTriples--select' :: RDF SP -> NodeSelector -> NodeSelector -> NodeSelector -> Triples-select' gr Nothing Nothing Nothing =-    triplesOf' gr--select' (SP (tsMap,_,_))   Nothing  (Just pSelector) Nothing  =-    Map.foldrWithKey findTripleWithP [] tsMap-    where-      findTripleWithP (s,p) oList ts = if pSelector p-                                       then map (Triple s p) oList ++ ts-                                       else ts--select' (SP (tsMap,_,_))    Nothing  Nothing  (Just oSelector) =-    Map.foldrWithKey findTripleWithS [] tsMap-    where-      findTripleWithS (s,p) oList ts = map (Triple s p) (filter oSelector oList) ++ ts--select' (SP (tsMap,_,_))    Nothing  (Just pSelector) (Just oSelector) =-    Map.foldrWithKey findTripleWithS [] tsMap-    where-      findTripleWithS (s,p) oList ts = if pSelector p-                                       then map (Triple s p) (filter oSelector oList) ++ ts-                                       else ts--select' (SP (tsMap,_,_))    (Just sSelector) Nothing  Nothing  =-    Map.foldrWithKey findTripleWithS [] tsMap-    where-      findTripleWithS (s,p) oList ts = if sSelector s-                                       then map (Triple s p) oList ++ ts-                                       else ts--select' (SP (tsMap,_,_))    (Just sSelector) (Just pSelector) Nothing =-    Map.foldrWithKey findTripleWithS [] tsMap-    where-      findTripleWithS (s,p) oList ts = if sSelector s && pSelector p-                                       then map (Triple s p) oList ++ ts-                                       else ts--select' (SP (tsMap,_,_))    (Just sSelector) Nothing  (Just oSelector) =-    Map.foldrWithKey findTripleWithS [] tsMap-    where-      findTripleWithS (s,p) oList ts = if sSelector s-                                        then map (Triple s p) (filter oSelector oList) ++ ts-                                        else ts--select' (SP (tsMap,_,_))    (Just sSelector) (Just pSelector) (Just oSelector) =-    Map.foldrWithKey findTripleWithS [] tsMap-    where-      findTripleWithS (s,p) oList ts = if sSelector s && pSelector p-                                       then map (Triple s p) (filter oSelector oList) ++ ts-                                       else ts--query' :: RDF SP -> Maybe Subject -> Maybe Predicate -> Maybe Object -> Triples-query' gr Nothing  Nothing  Nothing  =-    triplesOf' gr--query' (SP (tsMap,_,_))    Nothing  (Just p) Nothing  =-    Map.foldrWithKey findTripleWithP [] tsMap-    where-      findTripleWithP (s,p') oList ts = if p == p'-                                        then map (Triple s p) oList ++ ts-                                        else ts--query' (SP (tsMap,_,_))    Nothing  Nothing  (Just o) =-    Map.foldrWithKey findTripleWithS [] tsMap-    where-      findTripleWithS (s,p) oList ts = map (Triple s p) (filter (== o) oList) ++ ts--query' (SP (tsMap,_,_))    Nothing  (Just p) (Just o) =-    Map.foldrWithKey findTripleWithS [] tsMap-    where-      findTripleWithS (s,p') oList ts = if p == p'-                                        then map (Triple s p) (filter (== o) oList) ++ ts-                                        else ts--query' (SP (tsMap,_,_))    (Just s) Nothing  Nothing  =-    Map.foldrWithKey findTripleWithS [] tsMap-    where-      findTripleWithS (s',p) oList ts = if s == s'-                                        then map (Triple s p) oList ++ ts-                                        else ts---- optimal pattern for this SP instance-query' (SP (tsMap,_,_))    (Just s) (Just p) Nothing =-    (map (Triple s p) . Map.findWithDefault [] (s,p)) tsMap--query' (SP (tsMap,_,_))    (Just s) Nothing  (Just o) =-    Map.foldrWithKey findTripleWithS [] tsMap-    where-      findTripleWithS (s',p) oList ts = if s == s'-                                        then map (Triple s p) (filter (== o) oList) ++ ts-                                        else ts--query' (SP (tsMap,_,_))    (Just s) (Just p) (Just o) =-    Map.foldrWithKey findTripleWithS [] tsMap-    where-      findTripleWithS (s',p') oList ts = if s == s' && p == p'-                                        then map (Triple s p) (filter (== o) oList) ++ ts-                                        else ts
src/Data/RDF/Graph/TList.hs view
@@ -74,6 +74,8 @@   addPrefixMappings = addPrefixMappings'   empty             = empty'   mkRdf             = mkRdf'+  addTriple         = addTriple'+  removeTriple      = removeTriple'   triplesOf         = triplesOf'   uniqTriplesOf     = uniqTriplesOf'   select            = select'@@ -84,7 +86,8 @@ --  show ((TListC (ts, _, _))) = concatMap (\t -> show t ++ "\n") ts  showGraph' :: RDF TList -> [Char]-showGraph' ((TListC (ts, _, _))) = concatMap (\t -> show t ++ "\n") ts+-- showGraph' ((TListC (ts, _, _))) = concatMap (\t -> show t ++ "\n") ts+showGraph' gr = concatMap (\t -> show t ++ "\n") (expandTriples gr)  prefixMappings' :: RDF TList -> PrefixMappings prefixMappings' (TListC(_, _, pms)) = pms@@ -105,7 +108,17 @@ -- from the results of the select' and query' functions, since it is cheap to do -- there in most cases, but not when triplesOf' is called. mkRdf' :: Triples -> Maybe BaseUrl -> PrefixMappings -> RDF TList-mkRdf' ts baseURL pms = TListC(ts, baseURL, pms)+mkRdf' ts baseURL pms = TListC (ts, baseURL, pms)++addTriple' :: RDF TList -> Triple -> RDF TList+addTriple' (TListC (ts, bURL, preMapping)) t = TListC (t:ts,bURL,preMapping)++-- | yes, broken for now. use property tests to fix.+removeTriple' :: RDF TList -> Triple -> RDF TList+removeTriple' (TListC (ts, bURL, preMapping)) t =+  TListC (newTs,bURL,preMapping)+  where+    newTs = filter (/= t) ts  triplesOf' :: RDF TList -> Triples triplesOf' ((TListC(ts, _, _))) = ts
src/Data/RDF/Query.hs view
@@ -4,7 +4,7 @@   equalSubjects, equalPredicates, equalObjects,   subjectOf, predicateOf, objectOf, isEmpty,   rdfContainsNode, tripleContainsNode,-  subjectsWithPredicate, objectsOfPredicate,+  subjectsWithPredicate, objectsOfPredicate, uordered,    -- * RDF graph functions   isIsomorphic, isGraphIsomorphic, expandTriples, fromEither,@@ -92,6 +92,10 @@   case res of     (Left err) -> error (show err)     (Right rdf) -> rdf++-- |Convert a list of triples into a sorted list of unique triples.+uordered :: Triples -> Triples+uordered  =  sort . nub  -- graphFromEdges :: Ord key => [(node, key, [key])] -> (Graph, Vertex -> (node, key, [key]), key -> Maybe Vertex) 
src/Data/RDF/Types.hs view
@@ -26,7 +26,7 @@   RDF,    -- * Rdf type class-  Rdf(baseUrl,prefixMappings,addPrefixMappings,empty,mkRdf,triplesOf,uniqTriplesOf,select,query,showGraph),+  Rdf(baseUrl,prefixMappings,addPrefixMappings,empty,mkRdf,addTriple,removeTriple,triplesOf,uniqTriplesOf,select,query,showGraph),    -- * Parsing RDF   RdfParser(parseString,parseFile,parseURL),@@ -358,6 +358,12 @@   -- in the input depend on the particular RDF implementation.   mkRdf :: Triples -> Maybe BaseUrl -> PrefixMappings -> RDF rdfImpl +  -- |Adds a triple to an RDF graph.+  addTriple :: RDF rdfImpl -> Triple -> RDF rdfImpl++  -- |Removes all occurrences of a triple in an RDF graph.+  removeTriple :: RDF rdfImpl -> Triple -> RDF rdfImpl+   -- |Return all triples in the RDF, as a list.   --   -- Note that this function returns a list of triples in the RDF as they@@ -747,5 +753,7 @@ fileSchemeToFilePath (UNode fileScheme) =     if T.pack "file://" `T.isPrefixOf` fileScheme     then fmap (T.pack . Network.uriPath) (Network.parseURI (T.unpack fileScheme))-    else Nothing+    else if T.pack "http://" `T.isPrefixOf` fileScheme+         then fmap (T.pack . Network.uriPath) (Network.parseURI (T.unpack fileScheme))+         else Nothing fileSchemeToFilePath _ = Nothing
src/Rdf4hParseMain.hs view
@@ -5,12 +5,13 @@  module Main where -import Data.RDF.Types-import Data.RDF.Graph.TList-import Text.RDF.RDF4H.NTriplesParser-import Text.RDF.RDF4H.NTriplesSerializer-import Text.RDF.RDF4H.TurtleParser-import Text.RDF.RDF4H.TurtleSerializer+import Data.RDF+-- import Data.RDF.Types+-- import Data.RDF.Graph.TList+-- import Text.RDF.RDF4H.NTriplesParser+-- import Text.RDF.RDF4H.NTriplesSerializer+-- import Text.RDF.RDF4H.TurtleParser+-- import Text.RDF.RDF4H.TurtleSerializer  import qualified Data.Text as T import qualified Data.Text.IO as TIO@@ -82,6 +83,17 @@                                   >>=                                   \ (res :: Either ParseFailure (RDF TList)) ->                                     write outputFormat Nothing emptyPms res+         ("xml", True) -> parseURL (XmlParser mInputUri docUri)+                          inputUri+                          >>=+                          \ (res :: Either ParseFailure (RDF TList)) ->+                            write outputFormat docUri emptyPms res+         ("xml", False) -> (if inputUri /= "-" then+                                   parseFile (XmlParser mInputUri docUri) inputUri else+                                   liftM (parseString (XmlParser mInputUri docUri)) TIO.getContents)+                                  >>=+                                  \ (res :: Either ParseFailure (RDF TList)) ->+                                    write outputFormat docUri emptyPms res          (str, _) -> putStrLn ("Invalid format: " ++ str) >> exitFailure  write :: (Rdf a) => String -> Maybe T.Text -> PrefixMappings -> Either ParseFailure (RDF a) -> IO ()@@ -167,7 +179,8 @@  , Option "d"  ["debug"]                         (NoArg Debug)   "Print debug info (like INPUT-BASE-URI used, etc.)"  , Option "i"  ["input"]        (ReqArg InputFormat  "FORMAT") $ "Set input format/parser to one of:\n" ++                                                                    "  turtle      Turtle (default)\n" ++-                                                                   "  ntriples    N-Triples"+                                                                   "  ntriples    N-Triples\n" +++                                                                   "  xml         RDF/XML"  , Option "I"  ["input-base-uri"]  (ReqArg InputBaseUri "URI") $ "Set the input/parser base URI. '-' for none.\n" ++                                                                    "  Default is INPUT-BASE-URI argument value.\n\n" 
src/Text/RDF/RDF4H/Interact.hs view
@@ -18,7 +18,7 @@  import Data.RDF.Types hiding (baseUrl) import Data.RDF.Graph.TList()-import Data.RDF.Graph.HashMapS()+import Data.RDF.Graph.AdjHashMap()  import Text.RDF.RDF4H.NTriplesParser import Text.RDF.RDF4H.TurtleParser
src/Text/RDF/RDF4H/TurtleParser.hs view
@@ -8,13 +8,14 @@ where  import Data.Char (isLetter,isAlphaNum,toLower,toUpper)+import qualified Data.Map as Map+import Data.Map (Map) import Data.Maybe import Data.RDF.Types import Data.RDF.Namespace import Text.RDF.RDF4H.ParserUtils import Text.Parsec import Text.Parsec.Text-import qualified Data.Map as Map import qualified Data.Text as T import qualified Data.Text.IO as TIO import Data.Sequence(Seq, (|>))@@ -51,12 +52,13 @@    [Bool],           -- a stack of values to indicate that we're processing a (possibly nested) collection; top True indicates just started (on first element)    [Bool],           -- when in a collection, is it a subject collection or not    Bool,           -- when in a blank node property list, is it a subject collection or not-   Seq Triple)       -- the triples encountered while parsing; always added to on the right side+   Seq Triple,       -- the triples encountered while parsing; always added to on the right side+   Map String Int)  -- grammar rule: [1] turtleDoc t_turtleDoc :: GenParser ParseState (Seq Triple, PrefixMappings) t_turtleDoc =-  many t_statement >> (eof <?> "eof") >> getState >>= \(_, _, _, pms, _, _, _, _, _, ts) -> return (ts, pms)+  many t_statement >> (eof <?> "eof") >> getState >>= \(_, _, _, pms, _, _, _, _, _, ts,_) -> return (ts, pms)  -- grammar rule: [2] statement t_statement :: GenParser ParseState ()@@ -110,7 +112,7 @@      uriFrag <- t_iriref      void (many t_ws <?> "prefixID-whitespace")      void (char '.' <?> "end-of-prefixID-period")-     (bUrl, dUrl, _, PrefixMappings pms, _, _, _, _, _, _) <- getState+     (bUrl, dUrl, _, PrefixMappings pms, _, _, _, _, _, _, _) <- getState      updatePMs $ Just (PrefixMappings $ Map.insert pre (absolutizeUrl bUrl dUrl uriFrag) pms)      return () @@ -121,7 +123,7 @@      pre <- (many1 t_ws <?> "whitespace-after-@prefix") >> option T.empty t_pn_prefix      void (char ':' >> (many1 t_ws <?> "whitespace-after-@prefix-colon"))      uriFrag <- t_iriref-     (bUrl, dUrl, _, PrefixMappings pms, _, _, _, _, _, _) <- getState+     (bUrl, dUrl, _, PrefixMappings pms, _, _, _, _, _, _, _) <- getState      updatePMs $ Just (PrefixMappings $ Map.insert pre (absolutizeUrl bUrl dUrl uriFrag) pms)      return () @@ -160,7 +162,7 @@ t_pname_ns =do   pre <- option T.empty (try t_pn_prefix)   void (char ':')-  (bUrl, _, _, pms, _, _, _, _, _, _) <- getState+  (bUrl, _, _, pms, _, _, _, _, _, _, _) <- getState   case resolveQName bUrl pre pms of     Just n  -> return n     Nothing -> unexpected ("Cannot resolve QName prefix: " ++ T.unpack pre)@@ -226,18 +228,27 @@ -- [137s] BlankNode ::= BLANK_NODE_LABEL | ANON t_blankNode :: GenParser ParseState Node t_blankNode = do-  (try t_blank_node_label <|> t_anon)-  i <- nextIdCounter-  let node = BNodeGen i+  genID <- (try t_blank_node_label <|> (t_anon >> return ""))+  mp <- currGenIdLookup+  node <-+    case Map.lookup genID mp of+      Nothing -> do+        i <- nextIdCounter+        let node = BNodeGen i+        addGenIdLookup genID i+        return node+      Just i ->+        return $ BNodeGen i   return node  -- TODO replicate the recursion technique from [168s] for ((..)* something)? -- [141s] BLANK_NODE_LABEL ::= '_:' (PN_CHARS_U | [0-9]) ((PN_CHARS | '.')* PN_CHARS)?-t_blank_node_label :: GenParser ParseState ()+t_blank_node_label :: GenParser ParseState [Char] t_blank_node_label = do   void (string "_:")-  void (t_pn_chars_u <|> oneOf ['0'..'9'])-  optional $ try $ do+  firstChar <- (t_pn_chars_u <|> oneOf ['0'..'9'])+--  optional $ try $ do+  try $ do     ss <- option "" $ do             xs <- many (t_pn_chars <|> char '.')             if null xs@@ -245,7 +256,7 @@             else if last xs == '.'                  then unexpected "'.' at the end of a blank node label"                  else return xs-    return ss+    return (firstChar : ss)  -- [162s] ANON ::= '[' WS* ']' t_anon :: GenParser ParseState ()@@ -547,37 +558,44 @@ newBaseUrl Nothing               url = BaseUrl url newBaseUrl (Just (BaseUrl bUrl)) url = BaseUrl $! mkAbsoluteUrl bUrl url +currGenIdLookup :: GenParser ParseState (Map String Int)+currGenIdLookup = getState >>= \(_, _, _, _, _, _, _, _, _, _,genMap) -> return genMap++addGenIdLookup :: String -> Int -> GenParser ParseState ()+addGenIdLookup genId counter = getState >>= \(bUrl, dUrl, i, pms, ss, ps, cs, subjC, subjBNodeList, ts, genMap) ->+                  setState (bUrl, dUrl, i, pms, ss, ps, cs, subjC, subjBNodeList, ts, Map.insert genId counter genMap)+ currBaseUrl :: GenParser ParseState (Maybe BaseUrl)-currBaseUrl = getState >>= \(bUrl, _, _, _, _, _, _, _, _, _) -> return bUrl+currBaseUrl = getState >>= \(bUrl, _, _, _, _, _, _, _, _, _,_) -> return bUrl  currDocUrl :: GenParser ParseState (Maybe T.Text)-currDocUrl = getState >>= \(_, dUrl, _, _, _, _, _, _, _, _) -> return dUrl+currDocUrl = getState >>= \(_, dUrl, _, _, _, _, _, _, _, _,_) -> return dUrl  pushSubj :: Subject -> GenParser ParseState ()-pushSubj s = getState >>= \(bUrl, dUrl, i, pms, ss, ps, cs, subjC, subjBNodeList, ts) ->-                  setState (bUrl, dUrl, i, pms, s:ss, ps, cs, subjC, subjBNodeList, ts)+pushSubj s = getState >>= \(bUrl, dUrl, i, pms, ss, ps, cs, subjC, subjBNodeList, ts, genMap) ->+                  setState (bUrl, dUrl, i, pms, s:ss, ps, cs, subjC, subjBNodeList, ts, genMap)  popSubj :: GenParser ParseState Subject-popSubj = getState >>= \(bUrl, dUrl, i, pms, ss, ps, cs, subjC, subjBNodeList, ts) ->-                setState (bUrl, dUrl, i, pms, tail ss, ps, cs, subjC, subjBNodeList, ts) >>+popSubj = getState >>= \(bUrl, dUrl, i, pms, ss, ps, cs, subjC, subjBNodeList, ts, genMap) ->+                setState (bUrl, dUrl, i, pms, tail ss, ps, cs, subjC, subjBNodeList, ts, genMap) >>                   when (null ss) (error "Cannot pop subject off empty stack.") >>                   return (head ss)  pushPred :: Predicate -> GenParser ParseState ()-pushPred p = getState >>= \(bUrl, dUrl, i, pms, ss, ps, cs, subjC, subjBNodeList, ts) ->-                  setState (bUrl, dUrl, i, pms, ss, p:ps, cs, subjC, subjBNodeList, ts)+pushPred p = getState >>= \(bUrl, dUrl, i, pms, ss, ps, cs, subjC, subjBNodeList, ts, genMap) ->+                  setState (bUrl, dUrl, i, pms, ss, p:ps, cs, subjC, subjBNodeList, ts, genMap)  popPred :: GenParser ParseState Predicate-popPred = getState >>= \(bUrl, dUrl, i, pms, ss, ps, cs, subjC, subjBNodeList, ts) ->-                setState (bUrl, dUrl, i, pms, ss, tail ps, cs, subjC, subjBNodeList, ts) >>+popPred = getState >>= \(bUrl, dUrl, i, pms, ss, ps, cs, subjC, subjBNodeList, ts, genMap) ->+                setState (bUrl, dUrl, i, pms, ss, tail ps, cs, subjC, subjBNodeList, ts, genMap) >>                   when (null ps) (error "Cannot pop predicate off empty stack.") >>                   return (head ps)  isInColl :: GenParser ParseState Bool-isInColl = getState >>= \(_, _, _, _, _, _, cs, _, _, _) -> return . not . null $ cs+isInColl = getState >>= \(_, _, _, _, _, _, cs, _, _, _, _) -> return . not . null $ cs  isInSubjColl :: GenParser ParseState Bool-isInSubjColl = getState >>= \(_, _, _, _, _, _, _, xs, _, _) -> do+isInSubjColl = getState >>= \(_, _, _, _, _, _, _, xs, _, _, _) -> do                if null xs then return False else return (head xs)  {-@@ -588,20 +606,20 @@ -}  pushSubjColl :: GenParser ParseState ()-pushSubjColl = getState >>= \(bUrl, dUrl, i, pms, s, p, cs, subjC, subjBNodeList, ts) ->-                 setState (bUrl, dUrl, i, pms, s, p, cs, True:subjC, subjBNodeList, ts)+pushSubjColl = getState >>= \(bUrl, dUrl, i, pms, s, p, cs, subjC, subjBNodeList, ts, genMap) ->+                 setState (bUrl, dUrl, i, pms, s, p, cs, True:subjC, subjBNodeList, ts, genMap)  popColl :: GenParser ParseState ()-popColl = getState >>= \(bUrl, dUrl, i, pms, s, p, cs, subjC, subjBNodeList, ts) -> do+popColl = getState >>= \(bUrl, dUrl, i, pms, s, p, cs, subjC, subjBNodeList, ts, genMap) -> do                 when (null subjC) $ error "null in popColl"-                setState (bUrl, dUrl, i, pms, s, p, cs, tail subjC, subjBNodeList, ts)+                setState (bUrl, dUrl, i, pms, s, p, cs, tail subjC, subjBNodeList, ts, genMap)  pushObjColl :: GenParser ParseState ()-pushObjColl = getState >>= \(bUrl, dUrl, i, pms, s, p, cs, subjC, subjBNodeList, ts) ->-                 setState (bUrl, dUrl, i, pms, s, p, cs, False:subjC, subjBNodeList, ts)+pushObjColl = getState >>= \(bUrl, dUrl, i, pms, s, p, cs, subjC, subjBNodeList, ts,genMap) ->+                 setState (bUrl, dUrl, i, pms, s, p, cs, False:subjC, subjBNodeList, ts,genMap)  isSubjPropList :: GenParser ParseState Bool-isSubjPropList = getState >>= \(_, _, _, _, _, _, _, _, subjBNodeList, _) -> do+isSubjPropList = getState >>= \(_, _, _, _, _, _, _, _, subjBNodeList, _,_) -> do                 return subjBNodeList  {-@@ -611,12 +629,12 @@ -}  setSubjBlankNodePropList :: GenParser ParseState ()-setSubjBlankNodePropList = getState >>= \(bUrl, dUrl, i, pms, s, p, cs, subjC, _, ts) ->-                 setState (bUrl, dUrl, i, pms, s, p, cs, subjC, True, ts)+setSubjBlankNodePropList = getState >>= \(bUrl, dUrl, i, pms, s, p, cs, subjC, _, ts,genMap) ->+                 setState (bUrl, dUrl, i, pms, s, p, cs, subjC, True, ts,genMap)  setNotSubjBlankNodePropList :: GenParser ParseState ()-setNotSubjBlankNodePropList = getState >>= \(bUrl, dUrl, i, pms, s, p, cs, subjC, _, ts) ->-                 setState (bUrl, dUrl, i, pms, s, p, cs, subjC, True, ts)+setNotSubjBlankNodePropList = getState >>= \(bUrl, dUrl, i, pms, s, p, cs, subjC, _, ts,genMap) ->+                 setState (bUrl, dUrl, i, pms, s, p, cs, subjC, True, ts,genMap)  -- setObjBlankNodePropList :: GenParser ParseState () -- setObjBlankNodePropList = getState >>= \(bUrl, dUrl, i, pms, s, p, cs, subjC, _, ts) ->@@ -632,32 +650,32 @@  -- combines get_current and increment into a single function nextIdCounter :: GenParser ParseState Int-nextIdCounter = getState >>= \(bUrl, dUrl, i, pms, s, p, cs, subjC, subjBNodeList, ts) ->-                setState (bUrl, dUrl, i+1, pms, s, p, cs, subjC, subjBNodeList, ts) >> return i+nextIdCounter = getState >>= \(bUrl, dUrl, i, pms, s, p, cs, subjC, subjBNodeList, ts,genMap) ->+                setState (bUrl, dUrl, i+1, pms, s, p, cs, subjC, subjBNodeList, ts,genMap) >> return i  updatePMs :: Maybe PrefixMappings -> GenParser ParseState () updatePMs val = _modifyState no no val no no no  -- Register that we have begun processing a collection beginColl :: GenParser ParseState ()-beginColl = getState >>= \(bUrl, dUrl, i, pms, s, p, cs, subjC, subjBNodeList, ts) ->-            setState (bUrl, dUrl, i, pms, s, p, True:cs, subjC, subjBNodeList, ts)+beginColl = getState >>= \(bUrl, dUrl, i, pms, s, p, cs, subjC, subjBNodeList, ts,genMap) ->+            setState (bUrl, dUrl, i, pms, s, p, True:cs, subjC, subjBNodeList, ts,genMap)  onCollFirstItem :: GenParser ParseState Bool-onCollFirstItem = getState >>= \(_, _, _, _, _, _, cs, _, _, _) -> return (not (null cs) && head cs)+onCollFirstItem = getState >>= \(_, _, _, _, _, _, cs, _, _, _,_) -> return (not (null cs) && head cs)  collFirstItemProcessed :: GenParser ParseState ()-collFirstItemProcessed = getState >>= \(bUrl, dUrl, i, pms, s, p, _:cs, subjC, subjBNodeList, ts) ->-                         setState (bUrl, dUrl, i, pms, s, p, False:cs, subjC, subjBNodeList, ts)+collFirstItemProcessed = getState >>= \(bUrl, dUrl, i, pms, s, p, _:cs, subjC, subjBNodeList, ts,genMap) ->+                         setState (bUrl, dUrl, i, pms, s, p, False:cs, subjC, subjBNodeList, ts,genMap)  -- Register that a collection is finished being processed; the bool value -- in the monad is *not* the value that was popped from the stack, but whether -- we are still processing a parent collection or have finished processing -- all collections and are no longer in a collection at all. finishColl :: GenParser ParseState Bool-finishColl = getState >>= \(bUrl, dUrl, i, pms, s, p, cs, subjC, subjBNodeList, ts) ->+finishColl = getState >>= \(bUrl, dUrl, i, pms, s, p, cs, subjC, subjBNodeList, ts,genMap) ->              let cs' = drop 1 cs-             in setState (bUrl, dUrl, i, pms, s, p, cs', subjC, subjBNodeList, ts) >> return (not $ null cs')+             in setState (bUrl, dUrl, i, pms, s, p, cs', subjC, subjBNodeList, ts,genMap) >> return (not $ null cs')  -- Alias for Nothing for use with _modifyState calls, which can get very long with -- many Nothing values.@@ -667,8 +685,8 @@ -- Update the subject and predicate values of the ParseState to Nothing. resetSubjectPredicate :: GenParser ParseState () resetSubjectPredicate =-  getState >>= \(bUrl, dUrl, n, pms, _, _, cs, subjC, subjBNodeList, ts) ->-  setState (bUrl, dUrl, n, pms, [], [], cs, subjC, subjBNodeList, ts)+  getState >>= \(bUrl, dUrl, n, pms, _, _, cs, subjC, subjBNodeList, ts,genMap) ->+  setState (bUrl, dUrl, n, pms, [], [], cs, subjC, subjBNodeList, ts,genMap)  -- Modifies the current parser state by updating any state values among the parameters -- that have non-Nothing values.@@ -676,7 +694,7 @@                 Maybe Subject -> Maybe Predicate -> Maybe (Seq Triple) ->                 GenParser ParseState () _modifyState mb_bUrl mb_n mb_pms mb_subj mb_pred mb_trps =-  do (_bUrl, _dUrl, _n, _pms, _s, _p, _cs, _subjC, _subjBNodeList, _ts) <- getState+  do (_bUrl, _dUrl, _n, _pms, _s, _p, _cs, _subjC, _subjBNodeList, _ts,genMap) <- getState      setState (fromMaybe _bUrl mb_bUrl,               _dUrl,               maybe _n (const _n) mb_n,@@ -686,16 +704,16 @@               _cs,               _subjC,               _subjBNodeList,-              fromMaybe _ts mb_trps)+              fromMaybe _ts mb_trps,genMap)  addTripleForObject :: Object -> GenParser ParseState () addTripleForObject obj =-  do (bUrl, dUrl, i, pms, ss, ps, cs, subjC, subjBNodeList, ts) <- getState+  do (bUrl, dUrl, i, pms, ss, ps, cs, subjC, subjBNodeList, ts,genMap) <- getState      when (null ss) $        unexpected $ "No Subject with which to create triple for: " ++ show obj      when (null ps) $        unexpected $ "No Predicate with which to create triple for: " ++ show obj-     setState (bUrl, dUrl, i, pms, ss, ps, cs, subjC, subjBNodeList, ts |> Triple (head ss) (head ps) obj)+     setState (bUrl, dUrl, i, pms, ss, ps, cs, subjC, subjBNodeList, ts |> Triple (head ss) (head ps) obj,genMap)  -- |Parse the document at the given location URL as a Turtle document, using an optional @BaseUrl@ -- as the base URI, and using the given document URL as the URI of the Turtle document itself.@@ -731,14 +749,14 @@ parseFile' :: (Rdf a) => Maybe BaseUrl -> Maybe T.Text -> String -> IO (Either ParseFailure (RDF a)) parseFile' bUrl docUrl fpath = do   TIO.readFile fpath >>= \bs' -> return $ handleResult bUrl (runParser t_turtleDoc initialState (maybe "" T.unpack docUrl) bs')-  where initialState = (bUrl, docUrl, 1, PrefixMappings Map.empty, [], [], [], [], False, Seq.empty)+  where initialState = (bUrl, docUrl, 1, PrefixMappings Map.empty, [], [], [], [], False, Seq.empty,Map.empty)  -- |Parse the given string as a Turtle document. The arguments and return type have the same semantics -- as <parseURL>, except that the last @String@ argument corresponds to the Turtle document itself as -- a string rather than a location URI. parseString' :: (Rdf a) => Maybe BaseUrl -> Maybe T.Text -> T.Text -> Either ParseFailure (RDF a) parseString' bUrl docUrl ttlStr = handleResult bUrl (runParser t_turtleDoc initialState "" ttlStr)-  where initialState = (bUrl, docUrl, 1, PrefixMappings Map.empty, [], [], [], [], False, Seq.empty)+  where initialState = (bUrl, docUrl, 1, PrefixMappings Map.empty, [], [], [], [], False, Seq.empty,Map.empty)  handleResult :: Rdf a => Maybe BaseUrl -> Either ParseError (Seq Triple, PrefixMappings) -> Either ParseFailure (RDF a) handleResult bUrl result =
src/Text/RDF/RDF4H/XmlParser.hs view
@@ -18,7 +18,7 @@ import Data.RDF.Types (Rdf,RDF,RdfParser(..),Node(BNodeGen),BaseUrl(..),Triple(..),Triples,Subject,Predicate,Object,PrefixMappings(..),ParseFailure(ParseFailure),mkRdf,lnode,plainL,plainLL,typedL,unode,bnode,unodeValidate) import qualified Data.Text as T (Text,pack,unpack) import qualified Data.Text.IO as TIO-import Text.XML.HXT.Core (ArrowXml,ArrowIf,XmlTree,IfThen((:->)),(>.),(>>.),first,neg,(<+>),expandURI,getName,getAttrValue,getAttrValue0,getAttrl,hasAttrValue,hasAttr,constA,choiceA,getChildren,ifA,arr2A,second,hasName,isElem,isWhiteSpace,xshow,listA,isA,isText,getText,this,unlistA,orElse,sattr,mkelem,xreadDoc,runSLA)+import Text.XML.HXT.Core (ArrowXml,ArrowIf,XmlTree,IfThen((:->)),(>.),(>>.),first,neg,(<+>),expandURI,getName,getAttrValue,getAttrValue0,getAttrl,hasAttrValue,hasAttr,constA,choiceA,getChildren,ifA,arr2A,second,hasName,hasNamePrefix,isElem,isWhiteSpace,xshow,listA,isA,isText,getText,this,unlistA,orElse,sattr,mkelem,xreadDoc,runSLA) -- TODO: write QuickCheck tests for XmlParser instance for RdfParser.  data XmlParser = XmlParser (Maybe BaseUrl) (Maybe T.Text)@@ -114,11 +114,16 @@             rdf <- isElem <<< getChildren -< xml             bUrl <- arr (BaseUrl . T.pack) <<< ((getAttrValue0 "xml:base" <<< isElem <<< getChildren) `orElse` getAttrValue "transfer-URI") -< xml             prefixMap <- arr toPrefixMap <<< toAttrMap                  -< rdf-            triples <- parseDescription' >. id -< (bUrl, rdf)+            triples <- (parseDescription' >. failOnEmptyList >>> unlistA) -< (bUrl,rdf)             returnA -< mkRdf triples (Just bUrl) prefixMap   where toAttrMap = (getAttrl >>> (getName &&& (getChildren >>> getText))) >. id         toPrefixMap = PrefixMappings . Map.fromList . map (\(n, m) -> (T.pack (drop 6 n), T.pack m)) . filter (isPrefixOf "xmlns:" . fst) +        failOnEmptyList :: [b] -> [[b]]+        failOnEmptyList [] = []+        failOnEmptyList xs = [xs]++ -- |Read the initial state from an rdf element parseDescription' :: forall a. (ArrowXml a, ArrowState GParseState a) => a (BaseUrl, XmlTree) Triple parseDescription' = proc (bUrl, rdf) -> do@@ -163,41 +168,119 @@          <+> isA (== "rdf:parseType")          <+> isA (== "xml:base") +-- See: Issue http://www.w3.org/2000/03/rdf-tracking/#rdfms-rdf-names-use+--   section: Illegal or unusual use of names from the RDF namespace+--+-- test cases:+--   rdf-tests/rdf-xml/rdfms-rdf-names-use/test-017.rdf to+--   rdf-tests/rdf-xml/rdfms-rdf-names-use/test-032.rdf+--   rdf:Seq, rdf:Bag, rdf:Alt, rdf:Statement, rdf:Property, rdf:List+--   rdf:subject, rdf:predicate, rdf:object, rdf:type, rdf:value,+--   rdf:first, rdf:rest, rdf:_1, rdf:li+--+-- but in fact the wording at the above URL says:+--+-- "The WG reaffirmed its decision not to restrict names in the RDF+--  namespaces which are not syntactic. The WG decided that an RDF+--  processor SHOULD emit a warning when encountering names in the RDF+--  namespace which are not defined, but should otherwise behave+--  normally."+--+-- And that specifically:+--+--   <rdf:Description> +--     <rdf:foo>foo</rdf:foo>+--    </rdf:Description>+--+-- is equivalent to:+--  _:a <rdf:foo> "foo" .+--+-- And hence the use of `hasNamePrefix "rdf"`+isValidPropElemName :: (ArrowXml a, ArrowState GParseState a) => a XmlTree XmlTree+isValidPropElemName = hasNamePrefix "rdf"+  -- hasName "rdf:Seq"+  -- <+> hasName "rdf:Bag"+  -- <+> hasName "rdf:Alt"+  -- <+> hasName "rdf:Statement"+  -- <+> hasName "rdf:Property"+  -- <+> hasName "rdf:List"+  -- <+> hasName "rdf:subject"+  -- <+> hasName "rdf:predicate"+  -- <+> hasName "rdf:object"+  -- <+> hasName "rdf:type"+  -- <+> hasName "rdf:value"+  -- <+> hasName "rdf:first"+  -- <+> hasName "rdf:rest"+  -- <+> hasName "rdf:_1"+  -- <+> hasName "rdf:li"++ -- |Read a children of an rdf:Description element.  These correspond to the Predicate portion of the Triple parsePredicatesFromChildren :: forall a. (ArrowXml a, ArrowState GParseState a)                             => a (LParseState, XmlTree) Triple parsePredicatesFromChildren = updateState+    >>> validPropElementName     >>> choiceA         [ second (hasAttrValue "rdf:parseType" (== "Literal")) :-> arr2A parseAsLiteralTriple         , second (hasAttrValue "rdf:parseType" (== "Resource")) :-> (mkBlankNode &&& arr id >>> arr2A parseAsResource)         , second (hasAttrValue "rdf:parseType" (== "Collection")) :-> (listA (defaultA >>> arr id &&& mkBlankNode) >>> mkCollectionTriples >>> unlistA)         , second (hasAttr "rdf:datatype") :-> arr2A getTypedTriple-        , second (hasAttr "rdf:resource") :-> arr2A getResourceTriple---        , second (hasAttr "rdf:nodeID") >>> hasAttr "rdf:ID" :-> ERROR.+        -- for the following case, see rdfms-syntax-incomplete-error006+        , second (hasAttr "rdf:nodeID") :-> (neg (second (hasAttr "rdf:resource")) >>> arr2A getResourceTriple)         , second (hasAttr "rdf:nodeID") :-> arr2A getNodeIdTriple         , second (hasAttr "rdf:ID") :-> (arr2A mkRelativeNode &&& defaultA >>> arr2A reifyTriple >>> unlistA)+        , second (hasAttr "rdf:resource") :-> arr2A validPropElemNames+        , second isValidPropElemName :-> arr2A validPropElemNames         , second hasPredicateAttr :-> (defaultA <+> (mkBlankNode &&& arr id >>> arr2A parsePredicateAttr))         , this :-> defaultA         ]-  where defaultA = proc (state, predXml) -> do+        -- See: Issue http://www.w3.org/2000/03/rdf-tracking/#rdfms-rdf-names-use+        --   section: Illegal or unusual use of names from the RDF namespace+        --+        -- Avoid making blank nodes for some property names.+  where validPropElemNames state = proc (predXml) -> do+            p <- arr(unode . T.pack) <<< getName -< predXml+            o <- getAttrValue "rdf:resource" -< predXml+            returnA -< Triple (stateSubject state) p (unode (T.pack o))++        defaultA = proc (state, predXml) -> do                          p <- arr(unode . T.pack) <<< getName -< predXml                          t <- arr2A (arr2A . parseObjectsFromChildren) <<< second (second getChildren) -< (state, (p, predXml))                          returnA -< t+        -- parsePredicateAttr :: Node -> a (LParseState,XmlTree) Triple         parsePredicateAttr n = (second getName >>> arr (\(s, p) -> Triple (stateSubject s) ((unode . T.pack) p) n))                            <+> (first (arr (\s -> s { stateSubject = n })) >>> arr2A parsePredicatesFromAttr)         hasPredicateAttr = getAttrl >>> neg (getName >>> isMetaAttr) -parseObjectsFromChildren :: forall a. (ArrowXml a, ArrowState GParseState a)+-- See https://www.w3.org/2000/03/rdf-tracking/+-- Section "Issue rdfms-rdf-names-use: Illegal or unusual use of names from the RDF namespace"+validPropElementName :: (ArrowXml a, ArrowState GParseState a) => a (LParseState,XmlTree) (LParseState,XmlTree)+validPropElementName = proc (state,predXml) -> do+  neg (hasName "rdf:Description") -< predXml+  neg (hasName "rdf:RDF") -< predXml+  neg (hasName "rdf:ID") -< predXml+  neg (hasName "rdf:about") -< predXml+  neg (hasName "rdf:bagID") -< predXml+  neg (hasName "rdf:parseType") -< predXml+  neg (hasName "rdf:resource") -< predXml+  neg (hasName "rdf:nodeID") -< predXml+  neg (hasName "rdf:aboutEach") -< predXml+  neg (hasName "rdf:aboutEachPrefix") -< predXml+  returnA -< (state,predXml)++parseObjectsFromChildren :: forall a. (ArrowIf a, ArrowXml a, ArrowState GParseState a)                          => LParseState -> Predicate -> a XmlTree Triple parseObjectsFromChildren s p = choiceA     [ isText :-> (neg( isWhiteSpace) >>> getText >>> arr (Triple (stateSubject s) p . mkLiteralNode s))     , isElem :-> (parseObjectDescription)     ]-  where parseObjectDescription = proc desc -> do-                                      o <- mkNode s -< desc-                                      t0 <- arr (\(sub, (p', o)) -> Triple sub p' o) -< (stateSubject s, (p, o))-                                      t <- arr fst <+> (parseDescription <<< arr snd) -< (t0, (s { stateSubject = o }, desc))-                                      returnA -< t+  where parseObjectDescription =+          proc desc -> do+            _ <- (second (neg (hasAttr "rdf:nodeID")) &&& (second (neg (hasName "rdf:resource")))) -< (p,desc)+            o <- mkNode s -< desc+            t0 <- arr (\(sub, (p', o)) -> Triple sub p' o) -< (stateSubject s, (p, o))+            t <- arr fst <+> (parseDescription <<< arr snd) -< (t0, (s { stateSubject = o }, desc))+            returnA -< t  attachSubject :: Subject -> (Predicate, Object) -> Triple attachSubject s (p, o) = Triple s p o@@ -254,8 +337,22 @@                        , hasAttr "rdf:resource" :-> (attrExpandURI state "rdf:resource" >>> mkUNode)                        , hasAttr "rdf:nodeID" :-> (getAttrValue "rdf:nodeID" >>> arr (bnode . T.pack))                        , hasAttr "rdf:ID" :-> mkRelativeNode state-                       , this :-> mkBlankNode+                       , this :-> (validNodeElementName >>> mkBlankNode)                        ]++-- See https://www.w3.org/2000/03/rdf-tracking/+-- Section "Issue rdfms-rdf-names-use: Illegal or unusual use of names from the RDF namespace"+validNodeElementName :: (ArrowXml a, ArrowState GParseState a) => a XmlTree XmlTree+validNodeElementName = neg (hasName "rdf:RDF")+                       >>> neg (hasName "rdf:ID")+                       >>> neg (hasName "rdf:about")+                       >>> neg (hasName "rdf:bagID")+                       >>> neg (hasName "rdf:parseType")+                       >>> neg (hasName "rdf:resource")+                       >>> neg (hasName "rdf:nodeID")+                       >>> neg (hasName "rdf:li")+                       >>> neg (hasName "rdf:aboutEach")+                       >>> neg (hasName "rdf:aboutEachPrefix")  rdfXmlLiteral :: T.Text rdfFirst,rdfRest,rdfNil,rdfType,rdfStatement,rdfSubject,rdfPredicate,rdfObject :: Node
+ testsuite/tests/Data/RDF/Graph/AdjHashMap_Test.hs view
@@ -0,0 +1,33 @@+{-# LANGUAGE FlexibleInstances #-}++module Data.RDF.Graph.AdjHashMap_Test (triplesOf',uniqTriplesOf',empty',mkRdf',addTriple',removeTriple') where++import Data.RDF.Types+import Data.RDF.Graph.AdjHashMap (AdjHashMap)+import Data.RDF.GraphTestUtils+import qualified Data.Map as Map+import Control.Monad++import Test.QuickCheck++instance Arbitrary (RDF AdjHashMap) where+  arbitrary = liftM3 mkRdf arbitraryTs (return Nothing) (return $ PrefixMappings Map.empty)+  --coarbitrary = undefined++empty' :: RDF AdjHashMap+empty' = empty++mkRdf' :: Triples -> Maybe BaseUrl -> PrefixMappings -> RDF AdjHashMap+mkRdf' = mkRdf++triplesOf' :: RDF AdjHashMap -> Triples+triplesOf' = triplesOf++uniqTriplesOf' :: RDF AdjHashMap -> Triples+uniqTriplesOf' = uniqTriplesOf++addTriple' :: RDF AdjHashMap -> Triple -> RDF AdjHashMap+addTriple' = addTriple++removeTriple' :: RDF AdjHashMap -> Triple -> RDF AdjHashMap+removeTriple' = removeTriple
− testsuite/tests/Data/RDF/Graph/HashSP_Test.hs
@@ -1,28 +0,0 @@-{-# LANGUAGE FlexibleInstances #-}--module Data.RDF.Graph.HashSP_Test (triplesOf',uniqTriplesOf',empty',mkRdf') where--import Data.RDF.Types-import Data.RDF.Graph.HashMapSP (HashSP)-import Data.RDF.GraphTestUtils-import qualified Data.Map as Map-import Control.Monad--import Test.QuickCheck--instance Arbitrary HashSP--instance Arbitrary (RDF HashSP) where-  arbitrary = liftM3 mkRdf arbitraryTs (return Nothing) (return $ PrefixMappings Map.empty)--empty' :: RDF HashSP-empty' = empty--mkRdf' :: Triples -> Maybe BaseUrl -> PrefixMappings -> RDF HashSP-mkRdf' = mkRdf--triplesOf' :: RDF HashSP -> Triples-triplesOf' = triplesOf--uniqTriplesOf' :: RDF HashSP -> Triples-uniqTriplesOf' = uniqTriplesOf
− testsuite/tests/Data/RDF/Graph/HashS_Test.hs
@@ -1,29 +0,0 @@-{-# LANGUAGE FlexibleInstances #-}--module Data.RDF.Graph.HashS_Test (triplesOf',uniqTriplesOf',empty',mkRdf') where--import Data.RDF.Types-import Data.RDF.Graph.HashMapS (HashS)-import Data.RDF.GraphTestUtils-import qualified Data.Map as Map-import Control.Monad--import Test.QuickCheck--instance Arbitrary HashS--instance Arbitrary (RDF HashS) where-  arbitrary = liftM3 mkRdf arbitraryTs (return Nothing) (return $ PrefixMappings Map.empty)-  --coarbitrary = undefined--empty' :: RDF HashS-empty' = empty--mkRdf' :: Triples -> Maybe BaseUrl -> PrefixMappings -> RDF HashS-mkRdf' = mkRdf--triplesOf' :: RDF HashS -> Triples-triplesOf' = triplesOf--uniqTriplesOf' :: RDF HashS -> Triples-uniqTriplesOf' = uniqTriplesOf
− testsuite/tests/Data/RDF/Graph/SP_Test.hs
@@ -1,29 +0,0 @@-{-# LANGUAGE FlexibleInstances #-}--module Data.RDF.Graph.SP_Test (triplesOf',uniqTriplesOf',empty',mkRdf') where--import Data.RDF.Types-import Data.RDF.Graph.MapSP (SP)-import Data.RDF.GraphTestUtils-import qualified Data.Map as Map-import Control.Monad--import Test.QuickCheck--instance Arbitrary SP--instance Arbitrary (RDF SP) where-  arbitrary = liftM3 mkRdf arbitraryTs (return Nothing) (return $ PrefixMappings Map.empty)-  --coarbitrary = undefined--empty' :: RDF SP-empty' = empty--mkRdf' :: Triples -> Maybe BaseUrl -> PrefixMappings -> RDF SP-mkRdf' = mkRdf--triplesOf' :: RDF SP -> Triples-triplesOf' = triplesOf--uniqTriplesOf' :: RDF SP -> Triples-uniqTriplesOf' = uniqTriplesOf
testsuite/tests/Data/RDF/Graph/TList_Test.hs view
@@ -1,6 +1,6 @@ {-# LANGUAGE FlexibleInstances #-} -module Data.RDF.Graph.TList_Test (empty',triplesOf',uniqTriplesOf',mkRdf') where+module Data.RDF.Graph.TList_Test (empty',triplesOf',uniqTriplesOf',mkRdf',addTriple',removeTriple') where  import Control.Monad import qualified Data.Map as Map@@ -10,8 +10,6 @@ import Data.RDF.Types import Test.QuickCheck.Arbitrary -instance Arbitrary TList- instance Arbitrary (RDF TList) where   arbitrary = liftM3 mkRdf arbitraryTs (return Nothing) (return $ PrefixMappings Map.empty)   --coarbitrary = undefined@@ -27,3 +25,9 @@  uniqTriplesOf' :: RDF TList -> Triples uniqTriplesOf' = uniqTriplesOf++addTriple' :: RDF TList -> Triple -> RDF TList+addTriple' = addTriple++removeTriple' :: RDF TList -> Triple -> RDF TList+removeTriple' = removeTriple
testsuite/tests/Data/RDF/GraphTestUtils.hs view
@@ -1,6 +1,6 @@ {-# LANGUAGE DeriveGeneric #-} -module Data.RDF.GraphTestUtils where+module Data.RDF.GraphTestUtils (graphTests,arbitraryTs) where  import Data.RDF.Types import Data.RDF.Query@@ -14,7 +14,6 @@ import Control.Monad import GHC.Generics () import System.Directory (removeFile)-import System.IO.Unsafe(unsafePerformIO) import System.IO  import Test.Tasty@@ -25,11 +24,18 @@ --  property based quick check test cases         -- ---------------------------------------------------- -instance Arbitrary (RDF a)--graphTests :: (Arbitrary rdf, Rdf rdf)-           => TestName -> (RDF rdf -> Triples) -> (RDF rdf -> Triples) -> RDF rdf -> (Triples -> Maybe BaseUrl -> PrefixMappings -> RDF rdf) -> TestTree-graphTests testGroupName _triplesOf _uniqTriplesOf _empty _mkRdf = testGroup testGroupName+graphTests+  :: (Arbitrary (RDF rdf), Rdf rdf)+  => TestName+  -> (RDF rdf -> Triples) -- ^ triplesOf+  -> (RDF rdf -> Triples) -- ^ uniqTriplesOf+  -> RDF rdf -- ^ empty+  -> (Triples -> Maybe BaseUrl -> PrefixMappings -> RDF rdf) -- ^ mkRdf+  -> (RDF rdf -> Triple -> RDF rdf) -- ^ addTriple+  -> (RDF rdf -> Triple -> RDF rdf) -- ^ removeTriple+  -> TestTree+graphTests testGroupName _triplesOf _uniqTriplesOf _empty _mkRdf _addTriple _removeTriple =+  testGroup testGroupName             [               testProperty "empty"                      (p_empty _triplesOf _empty)             , testProperty "mkRdf_triplesOf"            (p_mkRdf_triplesOf _triplesOf _mkRdf)@@ -54,20 +60,45 @@             , testProperty "select_match_po"            (p_select_match_po _triplesOf)             , testProperty "select_match_spo"           (p_select_match_spo _triplesOf)             , testProperty "reversed RDF handle write"  (p_reverseRdfTest _mkRdf)++            -- adding and removing triples from a graph.+            , testProperty "add_triple" (p_add_triple _mkRdf _triplesOf _addTriple)+            , testProperty "remove_triple" (p_remove_triple _mkRdf _triplesOf _removeTriple)+            , testProperty "remove_triple_from_graph" (p_remove_triple_from_graph _mkRdf _triplesOf _removeTriple)+            , testProperty "remove_triple_from_singleton_graph_query_s" (p_remove_triple_from_singleton_graph_query_s _triplesOf _removeTriple)+            , testProperty "remove_triple_from_singleton_graph_query_p" (p_remove_triple_from_singleton_graph_query_p _triplesOf _removeTriple)+            , testProperty "remove_triple_from_singleton_graph_query_o" (p_remove_triple_from_singleton_graph_query_o _triplesOf _removeTriple)             ] +newtype SingletonGraph rdf = SingletonGraph { rdfGraph :: (RDF rdf) } +instance (Rdf rdf) => Arbitrary (SingletonGraph rdf) where+  arbitrary = do+    pref <- arbitraryPrefixMappings+    baseU' <- arbitraryBaseUrl+    baseU <- oneof [return (Just baseU'), return Nothing]+    t <- liftM3 triple arbitraryS arbitraryP arbitraryO+    return SingletonGraph { rdfGraph = (mkRdf [t] baseU pref) }++instance (Rdf rdf) => Show (SingletonGraph rdf) where+  show singletonGraph = showGraph (rdfGraph singletonGraph)+ instance Arbitrary BaseUrl where-  arbitrary = oneof $ map (return . BaseUrl . T.pack) ["http://example.com/a","http://asdf.org/b","http://asdf.org/c"]-  --coarbitrary = undefined+  arbitrary = arbitraryBaseUrl  instance Arbitrary PrefixMappings where-  arbitrary = oneof [return $ PrefixMappings Map.empty, return $ PrefixMappings $+  arbitrary = arbitraryPrefixMappings++arbitraryBaseUrl :: Gen BaseUrl+arbitraryBaseUrl = oneof $ map (return . BaseUrl . T.pack) ["http://example.com/a","http://asdf.org/b","http://asdf.org/c"]++arbitraryPrefixMappings :: Gen PrefixMappings+arbitraryPrefixMappings = oneof [return $ PrefixMappings Map.empty, return $ PrefixMappings $                           Map.fromAscList [(T.pack "eg1", T.pack "http://example.com/1"),                                            (T.pack "eg2", T.pack "http://example.com/2"),                                            (T.pack "eg3", T.pack "http://example.com/3")]]-  --coarbitrary = undefined + -- Test stubs, which just require the appropriate RDF impl function -- passed in to determine the implementation to be tested. @@ -187,6 +218,7 @@         all_ts = _triplesOf rdf         all_ts_sorted = uordered all_ts         results = uordered $ queryC rdf (mkPatternFn t)+        -- `notResults` is the difference of the two sets of triples         notResults = ldiff all_ts_sorted results       in         all (tripleCompareFn t) results &&@@ -259,6 +291,117 @@                    Just (\n -> n == predicateOf t),                    Just (\n -> n /= objectOf t)) +-- |adding a triple to a graph.+p_add_triple+  :: (Triples -> Maybe BaseUrl -> PrefixMappings -> RDF rdf)+  -> (RDF rdf -> Triples) -- ^ triplesOf+  -> (RDF rdf -> Triple -> RDF rdf) -- ^ addTriple+  -> Triples+  -> Maybe BaseUrl+  -> PrefixMappings+  -> Triple -- ^ new triple to be added+  -> Bool+p_add_triple _mkRdf _triplesOf _addTriple ts bUrl pms newTriple =+  uordered (newTriple : _triplesOf oldGr)+  == uordered (_triplesOf newGr) +  where+    oldGr = _mkRdf ts bUrl pms+    newGr =  _addTriple oldGr newTriple++-- |removing a triple that may or may not be in a graph. If it is not,+--  this operation is silently ignored.+p_remove_triple+  :: (Triples -> Maybe BaseUrl -> PrefixMappings -> RDF rdf)+  -> (RDF rdf -> Triples) -- ^ triplesOf+  -> (RDF rdf -> Triple -> RDF rdf) -- ^ removeTriple+  -> Triples+  -> Maybe BaseUrl+  -> PrefixMappings+  -> Triple -- ^ triple to be removed+  -> Bool+p_remove_triple _mkRdf _triplesOf _removeTriple ts bUrl pms tripleToBeRemoved =+  uordered (filter (/= tripleToBeRemoved) oldTriples)+  == uordered newTriples+  where+    oldGr      = _mkRdf ts bUrl pms+    newGr      = _removeTriple oldGr tripleToBeRemoved+    oldTriples = _triplesOf oldGr+    newTriples = _triplesOf newGr++-- |removing a triple from a graph. The new graph should not contain+-- any instances of the triple.+p_remove_triple_from_graph+  :: (Rdf rdf)+  => (Triples -> Maybe BaseUrl -> PrefixMappings -> RDF rdf)+  -> (RDF rdf -> Triples) -- ^ triplesOf+  -> (RDF rdf -> Triple -> RDF rdf) -- ^ removeTriple+  -> Triples+  -> Maybe BaseUrl+  -> PrefixMappings+  -> Property+p_remove_triple_from_graph  _mkRdf _triplesOf _removeTriple ts bUrl pms =+  classify (null ts) "p_remove_triple_from_graph tests were trivial" $+  forAll (tripleFromGen _triplesOf (_mkRdf ts bUrl pms)) f+  where+    f :: Maybe Triple -> Bool+    f Nothing = True+    f (Just tripleToBeRemoved) =+      p_remove_triple _mkRdf _triplesOf _removeTriple ts bUrl pms tripleToBeRemoved++-- TODO: refactor the following 3 functions.++-- |removing a triple from a graph that contained only that triple.+-- Performing a ((Just s) Nothing Nothing) query should return an+-- empty list.+p_remove_triple_from_singleton_graph_query_s+  :: (Rdf rdf)+  => (RDF rdf -> Triples) -- ^ triplesOf+  -> (RDF rdf -> Triple -> RDF rdf) -- ^ removeTriple+  -> SingletonGraph rdf+  -> Bool+p_remove_triple_from_singleton_graph_query_s _tripleOf _removeTriple singletonGraph =+  query newGr (Just s) Nothing Nothing == []+  where+    tripleInGraph@(Triple s _p _o) = head (_tripleOf (rdfGraph singletonGraph))+    newGr = _removeTriple (rdfGraph singletonGraph) tripleInGraph++-- |removing a triple from a graph that contained only that triple.+-- Performing a (Nothing (Just p) Nothing) query should return an+-- empty list.+p_remove_triple_from_singleton_graph_query_p+  :: (Rdf rdf)+  => (RDF rdf -> Triples) -- ^ triplesOf+  -> (RDF rdf -> Triple -> RDF rdf) -- ^ removeTriple+  -> SingletonGraph rdf+  -> Bool+p_remove_triple_from_singleton_graph_query_p _tripleOf _removeTriple singletonGraph =+  query newGr Nothing (Just p) Nothing == []+  where+    tripleInGraph@(Triple _s p _o) = head (_tripleOf (rdfGraph singletonGraph))+    newGr = _removeTriple (rdfGraph singletonGraph) tripleInGraph++-- |removing a triple from a graph that contained only that triple.+-- Performing a (Nothing Nothing (Just o)) query should return an+-- empty list.+p_remove_triple_from_singleton_graph_query_o+  :: (Rdf rdf)+  => (RDF rdf -> Triples) -- ^ triplesOf+  -> (RDF rdf -> Triple -> RDF rdf) -- ^ removeTriple+  -> SingletonGraph rdf+  -> Bool+p_remove_triple_from_singleton_graph_query_o _tripleOf _removeTriple singletonGraph =+  query newGr Nothing Nothing (Just o) == []+  where+    tripleInGraph@(Triple _s _p o) = head (_tripleOf (rdfGraph singletonGraph))+    newGr = _removeTriple (rdfGraph singletonGraph) tripleInGraph++  +-- p_query_match_none :: Rdf rdf => (Triples -> Maybe BaseUrl -> PrefixMappings -> RDF rdf) -> Triples -> Maybe BaseUrl -> PrefixMappings -> Bool+-- p_query_match_none  _mkRdf ts bUrl pms = uordered ts == uordered result+  -- where+  --   result = query (_mkRdf ts bUrl pms) Nothing Nothing Nothing++ equivNode :: (Node -> Node -> Bool) -> (Triple -> Node) -> Triple -> Triple -> Bool equivNode eqFn exFn t1 t2 = exFn t1 `eqFn` exFn t2 @@ -280,9 +423,9 @@         all (tripleCompareFn t) results &&         all (not . tripleCompareFn t) notResults -mkRdfWithDupe :: Rdf rdf => (RDF rdf -> Triples) -> (Triples -> Maybe BaseUrl -> PrefixMappings -> RDF rdf) -> RDF rdf -> Triple -> RDF rdf-mkRdfWithDupe _triplesOf _mkRdf rdf t = _mkRdf ts (baseUrl rdf) (prefixMappings rdf)-  where ts = t : _triplesOf rdf+-- mkRdfWithDupe :: Rdf rdf => (RDF rdf -> Triples) -> (Triples -> Maybe BaseUrl -> PrefixMappings -> RDF rdf) -> RDF rdf -> Triple -> RDF rdf+-- mkRdfWithDupe _triplesOf _mkRdf rdf t = _mkRdf ts (baseUrl rdf) (prefixMappings rdf)+--   where ts = t : _triplesOf rdf   -- Utility functions and test data ... --@@ -295,16 +438,16 @@ selectC :: Rdf rdf => RDF rdf -> (NodeSelector, NodeSelector, NodeSelector) -> Triples selectC rdf (s, p, o) = select rdf s p o -uncurry3 :: (a -> b -> c -> d) -> (a, b, c) -> d-uncurry3 fn (x, y, z) = fn x y z+-- uncurry3 :: (a -> b -> c -> d) -> (a, b, c) -> d+-- uncurry3 fn (x, y, z) = fn x y z -curry3 :: ((a, b, c) -> d) -> a -> b -> c -> d-curry3 fn x y z = fn (x, y, z)+-- curry3 :: ((a, b, c) -> d) -> a -> b -> c -> d+-- curry3 fn x y z = fn (x, y, z) -debug :: String -> Triples -> Bool-debug msg ts =-  unsafePerformIO $-    putStrLn msg >> mapM print ts >> return True+-- debug :: String -> Triples -> Bool+-- debug msg ts =+--   unsafePerformIO $+--     putStrLn msg >> mapM print ts >> return True  ldiff :: Triples -> Triples -> Triples ldiff l1 l2 = Set.toList $(Set.fromList l1) `Set.difference` Set.fromList l2@@ -318,10 +461,7 @@ sameObj :: Triple -> Triple -> Bool sameObj  t1 t2 = objectOf t1 == objectOf t2 --- Convert a list of triples into a sorted list of unique triples.-uordered :: Triples -> Triples-uordered  =  sort . nub-+-- |pick a random triple from an RDF graph if the graph is not empty. tripleFromGen :: Rdf rdf => (RDF rdf -> Triples) -> RDF rdf -> Gen (Maybe Triple) tripleFromGen _triplesOf rdf =   if null ts@@ -373,19 +513,19 @@   arbitrary = oneof $ map return unodes   --coarbitrary = undefined -arbitraryTNum :: Gen Int-arbitraryTNum = choose (0, maxN - 1)+-- arbitraryTNum :: Gen Int+-- arbitraryTNum = choose (0, maxN - 1)  arbitraryTs :: Gen Triples arbitraryTs = do   n <- sized (\_ -> choose (0, maxN))   sequence [arbitrary | _ <- [1..n]] -arbitraryT :: Gen Triple-arbitraryT = elements test_triples+-- arbitraryTriple :: Gen Triple+-- arbitraryTriple = elements test_triples -arbitraryN :: Gen Int-arbitraryN = choose (0, maxN - 1)+-- arbitraryN :: Gen Int+-- arbitraryN = choose (0, maxN - 1)  arbitraryS, arbitraryP, arbitraryO :: Gen Node arbitraryS = oneof $ map return $ unodes ++ bnodes
testsuite/tests/Test.hs view
@@ -3,9 +3,9 @@ import Test.Tasty (defaultMain,testGroup)  import qualified Data.RDF.Graph.TList_Test as TList-import qualified Data.RDF.Graph.HashS_Test as HashS-import qualified Data.RDF.Graph.HashSP_Test as HashSP-import qualified Data.RDF.Graph.SP_Test as SP+import qualified Data.RDF.Graph.AdjHashMap_Test as AdjHashMap+-- import qualified Data.RDF.Graph.HashSP_Test as HashSP+-- import qualified Data.RDF.Graph.SP_Test as SP -- very slow implementation, disabled for now. -- import qualified Data.RDF.Graph.TriplesPatriciaTree_Test as TriplesPatriciaTree import           Data.RDF.Types@@ -60,24 +60,28 @@           TList.uniqTriplesOf'           TList.empty'           TList.mkRdf'+          TList.addTriple'+          TList.removeTriple' -        , graphTests "HashS"-          HashS.triplesOf'-          HashS.uniqTriplesOf'-          HashS.empty'-          HashS.mkRdf'+        , graphTests "AdjHashMap"+          AdjHashMap.triplesOf'+          AdjHashMap.uniqTriplesOf'+          AdjHashMap.empty'+          AdjHashMap.mkRdf'+          AdjHashMap.addTriple'+          AdjHashMap.removeTriple' -        , graphTests "HashSP"-          HashSP.triplesOf'-          HashSP.uniqTriplesOf'-          HashSP.empty'-          HashSP.mkRdf'+        -- , graphTests "HashSP"+        --   HashSP.triplesOf'+        --   HashSP.uniqTriplesOf'+        --   HashSP.empty'+        --   HashSP.mkRdf' -        , graphTests "SP"-          SP.triplesOf'-          SP.uniqTriplesOf'-          SP.empty'-          SP.mkRdf'+        -- , graphTests "SP"+        --   SP.triplesOf'+        --   SP.uniqTriplesOf'+        --   SP.empty'+        --   SP.mkRdf'          -- , graphTests "TriplesPatriciaTree"         --   TriplesPatriciaTree.triplesOf'
testsuite/tests/Text/RDF/RDF4H/TurtleParser_ConformanceTest.hs view
@@ -6,7 +6,7 @@  -- Import common libraries to facilitate tests import Control.Monad (liftM)-import Data.RDF.GraphTestUtils+-- import Data.RDF.GraphTestUtils import Data.RDF.Query import Data.RDF.Graph.TList import Data.RDF.Types