module RDF where
-- Copyright (c) 2006-2007, Benja Fallenstein, Tuukka Hastrup
-- This file is part of Fenfire.
--
-- Fenfire is free software; you can redistribute it and/or modify it under
-- the terms of the GNU General Public License as published by
-- the Free Software Foundation; either version 2 of the License, or
-- (at your option) any later version.
--
-- Fenfire is distributed in the hope that it will be useful, but WITHOUT
-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-- Public License for more details.
--
-- You should have received a copy of the GNU General
-- Public License along with Fenfire; if not, write to the Free
-- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
-- MA 02111-1307 USA
import Cache
import Utils
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Maybe (fromMaybe, isJust)
import Data.Set (Set)
import qualified Data.Set as Set
data Node = URI String | PlainLiteral String deriving (Eq, Ord)
data Dir = Pos | Neg deriving (Eq, Ord, Show)
instance Show Node where
show (URI uri) = showURI [("rdfs", rdfs)] uri
show (PlainLiteral s) = "\"" ++ s ++ "\""
type Triple = (Node, Node, Node)
type Side = Map Node (Map Node (Set Node))
data Graph = Graph Side Side (Set Triple) deriving (Show, Eq)
instance Hashable Node where
hash (URI s) = hash s
hash (PlainLiteral s) = hash s
instance Hashable Dir where
hash Pos = 0
hash Neg = 1
rdfs = "http://www.w3.org/2000/01/rdf-schema#"
rdfs_label = URI "http://www.w3.org/2000/01/rdf-schema#label"
rdfs_seeAlso = URI "http://www.w3.org/2000/01/rdf-schema#seeAlso"
showURI ((short, long):xs) uri | take (length long) uri == long =
short ++ ":" ++ drop (length long) uri
| otherwise = showURI xs uri
showURI [] uri = "<" ++ uri ++ ">"
subject :: Triple -> Node
subject (s,_,_) = s
predicate :: Triple -> Node
predicate (_,p,_) = p
object :: Triple -> Node
object (_,_,o) = o
graphSide :: Dir -> Graph -> Side
graphSide Neg (Graph s _ _) = s
graphSide Pos (Graph _ s _) = s
hasConn :: Graph -> Node -> Node -> Dir -> Bool
hasConn g node prop dir = isJust $ do m <- Map.lookup node (graphSide dir g)
Map.lookup prop m
getOne :: Graph -> Node -> Node -> Dir -> Maybe Node
getOne g node prop dir = if null nodes then Nothing else Just $ head nodes
where nodes = Set.toList (getAll g node prop dir)
getAll :: Graph -> Node -> Node -> Dir -> Set Node
getAll g node prop dir =
Map.findWithDefault Set.empty prop $ getConns g node dir
getConns :: Graph -> Node -> Dir -> Map Node (Set Node)
getConns g node dir = Map.findWithDefault Map.empty node $ graphSide dir g
emptyGraph :: Graph
emptyGraph = Graph (Map.empty) (Map.empty) Set.empty
listToGraph :: [Triple] -> Graph
listToGraph = foldr insert emptyGraph
graphToList :: Graph -> [Triple]
graphToList (Graph _ _ triples) = Set.toAscList triples
mergeGraphs :: Op Graph
mergeGraphs g1 g2 = foldr insertVirtual g1 (graphToList g2)
insert :: Triple -> Graph -> Graph
insert t (Graph neg pos triples) =
insertVirtual t (Graph neg pos $ Set.insert t triples)
insertVirtual :: Triple -> Graph -> Graph
insertVirtual (s,p,o) (Graph neg pos triples) =
Graph (ins o p s neg) (ins s p o pos) triples where
ins a b c = Map.alter (Just . Map.alter (Just . Set.insert c . fromMaybe Set.empty) b . fromMaybe Map.empty) a -- Gack!!! Need to make more readable
delete :: Triple -> Graph -> Graph
delete (s,p,o) (Graph neg pos triples) =
Graph (del o p s neg) (del s p o pos) $ Set.delete (s,p,o) triples where
del a b c = Map.adjust (Map.adjust (Set.delete c) b) a
deleteAll :: Node -> Node -> Graph -> Graph
deleteAll s p g = dels s p os g where
dels s' p' (o':os') g' = dels s' p' os' (delete (s',p',o') g')
dels _ _ [] g' = g'
os = Set.toList $ getAll g s p Pos
update :: Triple -> Graph -> Graph
update (s,p,o) g = insert (s,p,o) $ deleteAll s p g
triple :: Dir -> (Node,Node,Node) -> Triple
triple Pos (s,p,o) = (s,p,o)
triple Neg (o,p,s) = (s,p,o)
fromNode :: Node -> String
fromNode (URI uri) = uri
fromNode (PlainLiteral s) = s
rev :: Dir -> Dir
rev Pos = Neg
rev Neg = Pos
mul :: Num a => Dir -> a -> a
mul Pos = id
mul Neg = negate