{-# LANGUAGE OverloadedStrings #-}---------------------------------------------------------------------------------- See end of this file for licence information.---------------------------------------------------------------------------------- |-- Module : Ruleset-- Copyright : (c) 2003, Graham Klyne, 2009 Vasili I Galchin, 2011, 2012 Douglas Burke-- License : GPL V2---- Maintainer : Douglas Burke-- Stability : experimental-- Portability : OverloadedStrings---- This module defines some datatypes and functions that are-- used to define rules and rulesets over RDF graphs.---- For the routines that accept a graph in N3 format, the following-- namespaces are pre-defined for use by the graph:-- @rdf:@ and @rdfs:@.----------------------------------------------------------------------------------moduleSwish.RDF.Ruleset(-- * Data types for RDF RulesetRDFFormula,RDFRule,RDFRuleMap,RDFClosure,RDFRuleset,RDFRulesetMap,nullRDFFormula,GraphClosure(..),makeGraphClosureRule,makeRDFGraphFromN3Builder,makeRDFFormula,makeRDFClosureRule-- * Create rules using Notation3 statements,makeN3ClosureRule,makeN3ClosureSimpleRule,makeN3ClosureModifyRule,makeN3ClosureAllocatorRule,makeNodeAllocTo-- * Debugging,graphClosureFwdApply,graphClosureBwdApply)whereimportSwish.Namespace(Namespace,ScopedName)importSwish.Namespace(makeNSScopedName,namespaceToBuilder)importSwish.QName(LName)importSwish.Rule(Formula(..),Rule(..),RuleMap)importSwish.Rule(fwdCheckInference,nullSN)importSwish.Ruleset(Ruleset(..),RulesetMap)importSwish.GraphClass(Label(..),Arc(..),LDGraph(..))importSwish.VarBinding(VarBindingModify(..))importSwish.VarBinding(makeVarBinding,applyVarBinding,joinVarBindings,vbmCompose,varBindingId)importSwish.RDF.Query(rdfQueryFind,rdfQueryBack,rdfQueryBackModify,rdfQuerySubs,rdfQuerySubsBlank)importSwish.RDF.Graph(RDFLabel(..),RDFGraph,makeBlank,newNodes,merge,allLabels,toRDFGraph)importSwish.RDF.VarBinding(RDFVarBinding,RDFVarBindingModify)importSwish.RDF.Parser.N3(parseN3)importSwish.RDF.Vocabulary(swishName,namespaceRDF,namespaceRDFS)importSwish.Utils.ListHelpers(equiv,flist)importData.List(nub)importData.Maybe(fromMaybe)importData.Monoid(Monoid(..))importqualifiedData.Text.Lazy.BuilderasB-------------------------------------------------------------- Datatypes for RDF ruleset-------------------------------------------------------------- | A named formula expressed as a RDF Graph.typeRDFFormula=FormulaRDFGraph-- | A named inference rule expressed in RDF.typeRDFRule=RuleRDFGraph-- | A 'LookupMap' for 'RDFRule' rules.typeRDFRuleMap=RuleMapRDFGraph-- | A 'GraphClosure' for RDF statements.typeRDFClosure=GraphClosureRDFLabel-- | A 'Ruleset' for RDF.typeRDFRuleset=RulesetRDFGraph-- | 'LookupMap' for 'RDFRuleset'.typeRDFRulesetMap=RulesetMapRDFGraph-------------------------------------------------------------- Declare null RDF formula-------------------------------------------------------------- | The null RDF formula.nullRDFFormula::FormulaRDFGraphnullRDFFormula=Formula{formName=nullSN"nullRDFGraph",formExpr=mempty}-------------------------------------------------------------- Datatype for graph closure rule-------------------------------------------------------------- |Datatype for constructing a graph closure ruledataGraphClosurelb=GraphClosure{nameGraphRule::ScopedName-- ^ Name of rule for proof display,ruleAnt::[Arclb]-- ^ Antecedent triples pattern-- (may include variable nodes),ruleCon::[Arclb]-- ^ Consequent triples pattern-- (may include variable nodes),ruleModify::VarBindingModifylblb-- ^ Structure that defines additional-- constraints and/or variable-- bindings based on other matched-- query variables. Matching the-- antecedents. Use 'varBindingId' if-- no additional variable constraints-- or bindings are added beyond those-- arising from graph queries.}instance(Labellb)=>Eq(GraphClosurelb)wherec1==c2=nameGraphRulec1==nameGraphRulec2&&ruleAntc1`equiv`ruleAntc2&&ruleConc1`equiv`ruleConc2instance(Labellb)=>Show(GraphClosurelb)whereshowc="GraphClosure "++show(nameGraphRulec)-------------------------------------------------------------- Define inference rule based on RDF graph closure rule-------------------------------------------------------------- |Define a value of type Rule based on an RDFClosure value.makeGraphClosureRule::GraphClosureRDFLabel->RuleRDFGraphmakeGraphClosureRulegrc=newrulewherenewrule=Rule{ruleName=nameGraphRulegrc,fwdApply=graphClosureFwdApplygrc,bwdApply=graphClosureBwdApplygrc,checkInference=fwdCheckInferencenewrule}-- | Forward chaining function based on RDF graph closure description---- Note: antecedents here are presumed to share bnodes.--graphClosureFwdApply::GraphClosureRDFLabel->[RDFGraph]->[RDFGraph]graphClosureFwdApplygrcgrs=letgr=ifnullgrsthenmemptyelsefoldl1addGraphsgrsvars=queryFind(ruleAntgrc)grvarm=vbmApply(ruleModifygrc)varscons=querySubsvarm(ruleCongrc)in{-
seq cons $
seq (trace "\ngraphClosureFwdApply") $
seq (traceShow "\nvars: " vars) $
seq (traceShow "\nvarm: " varm) $
seq (traceShow "\ncons: " cons) $
seq (trace "\n") $
-}-- Return null list or single result graph that is the union-- (not merge) of individual results:ifnullconsthen[]else[foldl1addGraphscons]-- cons {- don't merge results -}-- | Backward chaining function based on RDF graph closure descriptiongraphClosureBwdApply::GraphClosureRDFLabel->RDFGraph->[[RDFGraph]]graphClosureBwdApplygrcgr=letvars=rdfQueryBackModify(ruleModifygrc)$queryBack(ruleCongrc)gr-- This next function eliminates duplicate variable bindings.-- It is strictly redundant, but comparing variable-- bindings is much cheaper than comparing graphs.-- I don't know if many duplicate graphs will be result-- of exact duplicate variable bindings, so this may be-- not very effective.varn=mapnubvarsin-- The 'nub ante' below eliminates duplicate antecedent graphs,-- based on graph matching, which tests for equivalence under-- bnode renaming, with a view to reducing redundant arcs in-- the merged antecedent graph, hence less to prove in-- subsequent back-chaining steps.---- Each antecedent is reduced to a single RDF graph, when-- bwdApply specifies a list of expressions corresponding to-- each antecedent.[[foldl1merge(nubante)]|vs<-varn,letante=querySubsBlankvs(ruleAntgrc)]-------------------------------------------------------------- RDF graph query and substitution support functions------------------------------------------------------------queryFind::[ArcRDFLabel]->RDFGraph->[RDFVarBinding]queryFindqas=rdfQueryFind(toRDFGraphqas)queryBack::[ArcRDFLabel]->RDFGraph->[[RDFVarBinding]]queryBackqas=rdfQueryBack(toRDFGraphqas)querySubs::[RDFVarBinding]->[ArcRDFLabel]->[RDFGraph]querySubsvars=rdfQuerySubsvars.toRDFGraphquerySubsBlank::[RDFVarBinding]->[ArcRDFLabel]->[RDFGraph]querySubsBlankvars=rdfQuerySubsBlankvars.toRDFGraph-------------------------------------------------------------- Method for creating an RDF formula value from N3 text------------------------------------------------------------mkPrefix::Namespace->B.BuildermkPrefix=namespaceToBuilderprefixRDF::B.BuilderprefixRDF=mconcat[mkPrefixnamespaceRDF,mkPrefixnamespaceRDFS]-- |Helper function to parse a string containing Notation3-- and return the corresponding RDFGraph value.--makeRDFGraphFromN3Builder::B.Builder->RDFGraphmakeRDFGraphFromN3Builderb=lett=B.toLazyText(prefixRDF`mappend`b)incaseparseN3tNothingofLeftmsg->errormsgRightgr->gr-- |Create an RDF formula.makeRDFFormula::Namespace-- ^ namespace to which the formula is allocated->LName-- ^ local name for the formula in the namespace->B.Builder-- ^ graph in Notation 3 format->RDFFormulamakeRDFFormulascopelocalgr=Formula{formName=makeNSScopedNamescopelocal,formExpr=makeRDFGraphFromN3Buildergr}-------------------------------------------------------------- Create an RDF closure rule from supplied graphs-------------------------------------------------------------- |Constructs an RDF graph closure rule. That is, a rule that-- given some set of antecedent statements returns new statements-- that may be added to the graph.--makeRDFClosureRule::ScopedName-- ^ scoped name for the new rule->[RDFGraph]-- ^ RDFGraphs that are the entecedent of the rule.---- (Note: bnodes and variable names are assumed to be shared-- by all the entecedent graphs supplied. /is this right?/)->RDFGraph-- ^ the consequent graph->RDFVarBindingModify-- ^ is a variable binding modifier value that may impose-- additional conditions on the variable bindings that-- can be used for this inference rule, or which may-- cause new values to be allocated for unbound variables.-- These modifiers allow for certain inference patterns-- that are not captured by simple "closure rules", such-- as the allocation of bnodes corresponding to literals,-- and are an extension point for incorporating datatypes-- into an inference process.---- If no additional constraints or variable bindings are-- to be applied, use value 'varBindingId'--->RDFRulemakeRDFClosureRulesnameantgrscongrvmod=makeGraphClosureRuleGraphClosure{nameGraphRule=sname,ruleAnt=concatMapgetArcsantgrs,ruleCon=getArcscongr,ruleModify=vmod}-------------------------------------------------------------- Methods to create an RDF closure rule from N3 input---------------------------------------------------------------- These functions are used internally by Swish to construct-- rules from textual descriptions.-- |Constructs an RDF graph closure rule. That is, a rule that-- given some set of antecedent statements returns new statements-- that may be added to the graph. This is the basis for-- implementation of most of the inference rules given in the-- RDF formal semantics document.--makeN3ClosureRule::Namespace-- ^ namespace to which the rule is allocated->LName-- ^ local name for the rule in the namespace->B.Builder-- ^ the Notation3 representation-- of the antecedent graph. (Note: multiple antecedents-- can be handled by combining multiple graphs.)->B.Builder-- ^ the Notation3 representation of the consequent graph.->RDFVarBindingModify-- ^ a variable binding modifier value that may impose-- additional conditions on the variable bindings that-- can be used for this inference rule, or which may-- cause new values to be allocated for unbound variables.-- These modifiers allow for certain inference patterns-- that are not captured by simple closure rules, such-- as the allocation of bnodes corresponding to literals,-- and are an extension point for incorporating datatypes-- into an inference process.---- If no additional constraints or variable bindings are-- to be applied, use a value of 'varBindingId', or use-- 'makeN3ClosureSimpleRule'.->RDFRulemakeN3ClosureRulescopelocalantcon=makeRDFClosureRule(makeNSScopedNamescopelocal)[antgr]congrwhereantgr=makeRDFGraphFromN3Builderantcongr=makeRDFGraphFromN3Buildercon-- |Construct a simple RDF graph closure rule without-- additional node allocations or variable binding constraints.--makeN3ClosureSimpleRule::Namespace-- ^ namespace to which the rule is allocated->LName-- ^ local name for the rule in the namepace->B.Builder-- ^ the Notation3 representation-- of the antecedent graph. (Note: multiple antecedents-- can be handled by combining multiple graphs.)->B.Builder-- ^ the Notation3 representation of the consequent graph.->RDFRulemakeN3ClosureSimpleRulescopelocalantcon=makeN3ClosureRulescopelocalantconvarBindingId-- |Constructs an RDF graph closure rule that incorporates-- a variable binding filter and a variable binding modifier.--makeN3ClosureModifyRule::Namespace-- ^ namespace to which the rule is allocated->LName-- ^ local name for the rule in the given namespace->B.Builder-- ^ the Notation3 representation-- of the antecedent graph. (Note: multiple antecedents-- can be handled by combining multiple graphs.)->B.Builder-- ^ the Notation3 representation of the consequent graph.->RDFVarBindingModify-- ^ a variable binding modifier value that may impose-- additional conditions on the variable bindings that-- can be used for this inference rule (@vflt@).---- These modifiers allow for certain inference patterns-- that are not captured by simple closure rules, such-- as deductions that pertain only to certain kinds of-- nodes in a graph.->RDFVarBindingModify-- ^ a variable binding modifier that is applied to the-- variable bindings obtained, typically to create some-- additional variable bindings. This is applied before-- the preceeding filter rule (@vflt@).->RDFRulemakeN3ClosureModifyRulescopelocalantconvfltvmod=makeN3ClosureRulescopelocalantconmodcwheremodc=fromMaybevarBindingId$vbmComposevmodvflt{-
makeRDFClosureRule (ScopedName scope local) [antgr] congr modc
where
antgr = makeRDFGraphFromN3String ant
congr = makeRDFGraphFromN3String con
modc = case vbmCompose vmod vflt of
Just x -> x
Nothing -> varBindingId
-}-- |Construct an RDF graph closure rule with a bnode allocator.---- This function is rather like 'makeN3ClosureModifyRule', except that-- the variable binding modifier is a function from the variables in-- the variables and bnodes contained in the antecedent graph.--makeN3ClosureAllocatorRule::Namespace-- ^ namespace to which the rule is allocated->LName-- ^ local name for the rule in the given namespace->B.Builder-- ^ the Notation3 representation-- of the antecedent graph. (Note: multiple antecedents-- can be handled by combining multiple graphs.)->B.Builder-- ^ the Notation3 representation of the consequent graph.->RDFVarBindingModify-- ^ variable binding modifier value that may impose-- additional conditions on the variable bindings that-- can be used for this inference rule (@vflt@).->([RDFLabel]->RDFVarBindingModify)-- ^ function applied to a list of nodes to yield a-- variable binding modifier value.---- The supplied parameter is applied to a list of all of-- the variable nodes (including all blank nodes) in the-- antecedent graph, and then composed with the @vflt@-- value. This allows any node allocation-- function to avoid allocating any blank nodes that-- are already used in the antecedent graph.-- (See 'makeNodeAllocTo').->RDFRulemakeN3ClosureAllocatorRulescopelocalantconvfltaloc=makeRDFClosureRule(makeNSScopedNamescopelocal)[antgr]congrmodcwhereantgr=makeRDFGraphFromN3Builderantcongr=makeRDFGraphFromN3Builderconvmod=aloc(allLabelslabelIsVarantgr)modc=fromMaybevarBindingId$vbmComposevmodvflt-------------------------------------------------------------- Query binding modifier for "allocated to" logic-------------------------------------------------------------- |This function defines a variable binding modifier that-- allocates a new blank node for each value bound to-- a query variable, and binds it to another variable-- in each query binding.---- This provides a single binding for query variables that would-- otherwise be unbound by a query. For example, consider the-- inference pattern:-- -- > ?a hasUncle ?c => ?a hasFather ?b . ?b hasBrother ?c .-- -- For a given @?a@ and @?c@, there is insufficient information-- here to instantiate a value for variable @?b@. Using this-- function as part of a graph instance closure rule allows-- forward chaining to allocate a single bnode for each-- occurrence of @?a@, so that given:-- -- > Jimmy hasUncle Fred .-- > Jimmy hasUncle Bob .---- leads to exactly one bnode inference of:---- > Jimmy hasFather _:f .---- giving:---- > Jimmy hasFather _:f .-- > _:f hasBrother Fred .-- > _:f hasBrother Bob .---- rather than:---- > Jimmy hasFather _:f1 .-- > _:f1 hasBrother Fred .-- > Jimmy hasFather _:f2 .-- > _:f2 hasBrother Bob .---- This form of constrained allocation of bnodes is also required for-- some of the inference patterns described by the RDF formal semantics,-- particularly those where bnodes are substituted for URIs or literals.--makeNodeAllocTo::RDFLabel-- ^ variable node to which a new blank node is bound->RDFLabel-- ^ variable which is bound in each query to a graph-- node to which new blank nodes are allocated.->[RDFLabel]->RDFVarBindingModifymakeNodeAllocTobindvaralocvarexbnode=VarBindingModify{vbmName=swishName"makeNodeAllocTo",vbmApply=applyNodeAllocTobindvaralocvarexbnode,vbmVocab=[alocvar,bindvar],vbmUsage=[[bindvar]]}-- Auxiliary function that performs the node allocation defined-- by makeNodeAllocTo.---- bindvar is a variable node to which a new blank node is bound-- alocvar is a variable which is bound in each query to a graph-- node to which new blank nodes are allocated.-- exbnode is a list of existing blank nodes, to be avoided by-- the new blank node allocator.-- vars is a list of variable bindings to which new bnode-- allocations for the indicated bindvar are to be added.--applyNodeAllocTo::RDFLabel->RDFLabel->[RDFLabel]->[RDFVarBinding]->[RDFVarBinding]applyNodeAllocTobindvaralocvarexbnodevars=letapp=applyVarBindingalocnodes=zip(nub$flist(mapappvars)alocvar)(newNodes(makeBlankbindvar)exbnode)newvbvar=joinVarBindings(makeVarBinding$head[[(bindvar,b)]|(v,b)<-alocnodes,appvaralocvar==v])varinmapnewvbvars------------------------------------------------------------------------------------ Copyright (c) 2003, Graham Klyne, 2009 Vasili I Galchin,-- 2011, 2012 Douglas Burke -- All rights reserved.---- This file is part of Swish.---- Swish 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.---- Swish 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 Swish; if not, write to:-- The Free Software Foundation, Inc.,-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA----------------------------------------------------------------------------------