    {-# LANGUAGE CPP #-}
    {-# LANGUAGE OverloadedStrings #-}

    --------------------------------------------------------------------------------
    --  See end of this file for licence information.
    --------------------------------------------------------------------------------
    -- |
    --  Module      :  Ruleset
    --  Copyright   :  (c) 2003, Graham Klyne, 2009 Vasili I Galchin,
    --                 2011, 2012, 2014, 2016 Douglas Burke
    --  License     :  GPL V2
    --
    --  Maintainer  :  Douglas Burke
    --  Stability   :  experimental
    --  Portability :  CPP, 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:@.
    --
    --------------------------------------------------------------------------------

    module Swish.RDF.Ruleset
        (
         -- * Data types for RDF Ruleset
         RDFFormula, RDFRule, RDFRuleMap
        , RDFClosure, RDFRuleset, RDFRulesetMap
        , nullRDFFormula
        , GraphClosure(..), makeGraphClosureRule
        , makeRDFGraphFromN3Builder
        , makeRDFFormula
        , makeRDFClosureRule
          -- * Create rules using Notation3 statements
        , makeN3ClosureRule
        , makeN3ClosureSimpleRule
        , makeN3ClosureModifyRule
        , makeN3ClosureAllocatorRule
        , makeNodeAllocTo
          -- * Debugging
        , graphClosureFwdApply, graphClosureBwdApply
        )
    where

    import Swish.Namespace (Namespace, ScopedName)
    import Swish.Namespace (makeNSScopedName, namespaceToBuilder)
    import Swish.QName (LName)
    import Swish.Rule (Formula(..), Rule(..), RuleMap)
    import Swish.Rule (fwdCheckInference, nullSN)
    import Swish.Ruleset (Ruleset(..), RulesetMap)
    import Swish.GraphClass (Label(..), ArcSet, LDGraph(..))
    import Swish.VarBinding (VarBindingModify(..))
    import Swish.VarBinding (makeVarBinding, applyVarBinding, joinVarBindings, vbmCompose, varBindingId)

    import Swish.RDF.Query
        ( rdfQueryFind
        , rdfQueryBack, rdfQueryBackModify
        , rdfQuerySubs
        , rdfQuerySubsBlank
        )

    import Swish.RDF.Graph
        ( RDFLabel(..), RDFGraph, RDFArcSet
        , makeBlank, newNodes
        , merge, allLabels
        , toRDFGraph)

    import Swish.RDF.VarBinding (RDFVarBinding, RDFVarBindingModify)
    import Swish.RDF.Parser.N3 (parseN3)

    import Swish.RDF.Vocabulary (swishName, namespaceRDF, namespaceRDFS)

    import Swish.Utils.ListHelpers (flist)

    import Data.List (nub)
    import Data.Maybe (fromMaybe)

    #if (!defined(__GLASGOW_HASKELL__)) || (__GLASGOW_HASKELL__ < 710)
    import Data.Monoid (Monoid(..))
    #endif

    import qualified Data.Set as S
    import qualified Data.Text.Lazy.Builder as B

    ------------------------------------------------------------
    --  Datatypes for RDF ruleset
    ------------------------------------------------------------

    -- | A named formula expressed as a RDF Graph.
    type RDFFormula     = Formula RDFGraph

    -- | A named inference rule expressed in RDF.
    type RDFRule        = Rule RDFGraph

    -- | A map for 'RDFRule' rules.
    type RDFRuleMap     = RuleMap RDFGraph

    -- | A 'GraphClosure' for RDF statements.
    type RDFClosure     = GraphClosure RDFLabel

    -- | A 'Ruleset' for RDF.
    type RDFRuleset     = Ruleset RDFGraph

    -- | A map for 'RDFRuleset'.
    type RDFRulesetMap  = RulesetMap RDFGraph

    ------------------------------------------------------------
    --  Declare null RDF formula
    ------------------------------------------------------------

    -- | The null RDF formula.
    nullRDFFormula :: Formula RDFGraph
    nullRDFFormula :: Formula RDFGraph
    nullRDFFormula = Formula
        { formName :: ScopedName
    formName = LName -> ScopedName
    nullSN LName
    "nullRDFGraph"
        , formExpr :: RDFGraph
    formExpr = RDFGraph
    forall a. Monoid a => a
    mempty
        }

    ------------------------------------------------------------
    --  Datatype for graph closure rule
    ------------------------------------------------------------

    -- |Datatype for constructing a graph closure rule
    data GraphClosure lb = GraphClosure
        { forall lb. GraphClosure lb -> ScopedName
    nameGraphRule :: ScopedName   -- ^ Name of rule for proof display
        , forall lb. GraphClosure lb -> ArcSet lb
    ruleAnt       :: ArcSet lb    -- ^ Antecedent triples pattern
                                        --   (may include variable nodes)
        , forall lb. GraphClosure lb -> ArcSet lb
    ruleCon       :: ArcSet lb    -- ^ Consequent triples pattern
                                        --   (may include variable nodes)
        , forall lb. GraphClosure lb -> VarBindingModify lb lb
    ruleModify    :: VarBindingModify lb lb
                                        -- ^ 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.
        }

    -- | Equality is based on the closure rule, anrecedents and
    --   consequents.
    instance (Label lb) => Eq (GraphClosure lb) where
        GraphClosure lb
    c1 == :: GraphClosure lb -> GraphClosure lb -> Bool
    == GraphClosure lb
    c2 = GraphClosure lb -> ScopedName
    forall lb. GraphClosure lb -> ScopedName
    nameGraphRule GraphClosure lb
    c1 ScopedName -> ScopedName -> Bool
    forall a. Eq a => a -> a -> Bool
    == GraphClosure lb -> ScopedName
    forall lb. GraphClosure lb -> ScopedName
    nameGraphRule GraphClosure lb
    c2 Bool -> Bool -> Bool
    &&
                   GraphClosure lb -> ArcSet lb
    forall lb. GraphClosure lb -> ArcSet lb
    ruleAnt GraphClosure lb
    c1 ArcSet lb -> ArcSet lb -> Bool
    forall a. Eq a => a -> a -> Bool
    == GraphClosure lb -> ArcSet lb
    forall lb. GraphClosure lb -> ArcSet lb
    ruleAnt GraphClosure lb
    c2 Bool -> Bool -> Bool
    &&
                   GraphClosure lb -> ArcSet lb
    forall lb. GraphClosure lb -> ArcSet lb
    ruleCon GraphClosure lb
    c1 ArcSet lb -> ArcSet lb -> Bool
    forall a. Eq a => a -> a -> Bool
    == GraphClosure lb -> ArcSet lb
    forall lb. GraphClosure lb -> ArcSet lb
    ruleCon GraphClosure lb
    c2

    instance Show (GraphClosure lb) where
        show :: GraphClosure lb -> String
    show GraphClosure lb
    c = String
    "GraphClosure " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ ScopedName -> String
    forall a. Show a => a -> String
    show (GraphClosure lb -> ScopedName
    forall lb. GraphClosure lb -> ScopedName
    nameGraphRule GraphClosure lb
    c)

    ------------------------------------------------------------
    --  Define inference rule based on RDF graph closure rule
    ------------------------------------------------------------

    -- |Define a value of type Rule based on an RDFClosure value.
    makeGraphClosureRule :: GraphClosure RDFLabel -> Rule RDFGraph
    makeGraphClosureRule :: GraphClosure RDFLabel -> Rule RDFGraph
    makeGraphClosureRule GraphClosure RDFLabel
    grc = Rule RDFGraph
    newrule
        where
            newrule :: Rule RDFGraph
    newrule = Rule
                { ruleName :: ScopedName
    ruleName       = GraphClosure RDFLabel -> ScopedName
    forall lb. GraphClosure lb -> ScopedName
    nameGraphRule GraphClosure RDFLabel
    grc
                , fwdApply :: [RDFGraph] -> [RDFGraph]
    fwdApply       = GraphClosure RDFLabel -> [RDFGraph] -> [RDFGraph]
    graphClosureFwdApply GraphClosure RDFLabel
    grc
                , bwdApply :: RDFGraph -> [[RDFGraph]]
    bwdApply       = GraphClosure RDFLabel -> RDFGraph -> [[RDFGraph]]
    graphClosureBwdApply GraphClosure RDFLabel
    grc
                , checkInference :: [RDFGraph] -> RDFGraph -> Bool
    checkInference = Rule RDFGraph -> [RDFGraph] -> RDFGraph -> Bool
    forall ex. Eq ex => Rule ex -> [ex] -> ex -> Bool
    fwdCheckInference Rule RDFGraph
    newrule
                }

    -- | Forward chaining function based on RDF graph closure description
    --
    --  Note:  antecedents here are presumed to share bnodes.
    --
    graphClosureFwdApply ::
      GraphClosure RDFLabel
      -> [RDFGraph]
      -> [RDFGraph]
    graphClosureFwdApply :: GraphClosure RDFLabel -> [RDFGraph] -> [RDFGraph]
    graphClosureFwdApply GraphClosure RDFLabel
    grc [RDFGraph]
    grs =
        let gr :: RDFGraph
    gr   = if [RDFGraph] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [RDFGraph]
    grs then RDFGraph
    forall a. Monoid a => a
    mempty else (RDFGraph -> RDFGraph -> RDFGraph) -> [RDFGraph] -> RDFGraph
    forall a. (a -> a -> a) -> [a] -> a
    forall (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
    foldl1 RDFGraph -> RDFGraph -> RDFGraph
    forall (lg :: * -> *) lb.
    (LDGraph lg lb, Ord lb) =>
    lg lb -> lg lb -> lg lb
    addGraphs [RDFGraph]
    grs
            vars :: [RDFVarBinding]
    vars = RDFArcSet -> RDFGraph -> [RDFVarBinding]
    queryFind (GraphClosure RDFLabel -> RDFArcSet
    forall lb. GraphClosure lb -> ArcSet lb
    ruleAnt GraphClosure RDFLabel
    grc) RDFGraph
    gr
            varm :: [RDFVarBinding]
    varm = VarBindingModify RDFLabel RDFLabel
    -> [RDFVarBinding] -> [RDFVarBinding]
    forall a b.
    VarBindingModify a b -> [VarBinding a b] -> [VarBinding a b]
    vbmApply (GraphClosure RDFLabel -> VarBindingModify RDFLabel RDFLabel
    forall lb. GraphClosure lb -> VarBindingModify lb lb
    ruleModify GraphClosure RDFLabel
    grc) [RDFVarBinding]
    vars
            cons :: [RDFGraph]
    cons = [RDFVarBinding] -> RDFArcSet -> [RDFGraph]
    querySubs [RDFVarBinding]
    varm (GraphClosure RDFLabel -> RDFArcSet
    forall lb. GraphClosure lb -> ArcSet lb
    ruleCon GraphClosure RDFLabel
    grc)
        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:
            if [RDFGraph] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [RDFGraph]
    cons then [] else [(RDFGraph -> RDFGraph -> RDFGraph) -> [RDFGraph] -> RDFGraph
    forall a. (a -> a -> a) -> [a] -> a
    forall (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
    foldl1 RDFGraph -> RDFGraph -> RDFGraph
    forall (lg :: * -> *) lb.
    (LDGraph lg lb, Ord lb) =>
    lg lb -> lg lb -> lg lb
    addGraphs [RDFGraph]
    cons]
            -- cons {- don't merge results -}

    -- | Backward chaining function based on RDF graph closure description
    graphClosureBwdApply :: GraphClosure RDFLabel -> RDFGraph -> [[RDFGraph]]
    graphClosureBwdApply :: GraphClosure RDFLabel -> RDFGraph -> [[RDFGraph]]
    graphClosureBwdApply GraphClosure RDFLabel
    grc RDFGraph
    gr =
        let vars :: [[RDFVarBinding]]
    vars = VarBindingModify RDFLabel RDFLabel
    -> [[RDFVarBinding]] -> [[RDFVarBinding]]
    forall a b.
    VarBindingModify a b -> [[VarBinding a b]] -> [[VarBinding a b]]
    rdfQueryBackModify (GraphClosure RDFLabel -> VarBindingModify RDFLabel RDFLabel
    forall lb. GraphClosure lb -> VarBindingModify lb lb
    ruleModify GraphClosure RDFLabel
    grc) ([[RDFVarBinding]] -> [[RDFVarBinding]])
    -> [[RDFVarBinding]] -> [[RDFVarBinding]]
    forall a b. (a -> b) -> a -> b
    $
                   RDFArcSet -> RDFGraph -> [[RDFVarBinding]]
    queryBack (GraphClosure RDFLabel -> RDFArcSet
    forall lb. GraphClosure lb -> ArcSet lb
    ruleCon GraphClosure RDFLabel
    grc) RDFGraph
    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 :: [[RDFVarBinding]]
    varn = ([RDFVarBinding] -> [RDFVarBinding])
    -> [[RDFVarBinding]] -> [[RDFVarBinding]]
    forall a b. (a -> b) -> [a] -> [b]
    map [RDFVarBinding] -> [RDFVarBinding]
    forall a. Eq a => [a] -> [a]
    nub [[RDFVarBinding]]
    vars
        in
            --  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.
            [ [(RDFGraph -> RDFGraph -> RDFGraph) -> [RDFGraph] -> RDFGraph
    forall a. (a -> a -> a) -> [a] -> a
    forall (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
    foldl1 RDFGraph -> RDFGraph -> RDFGraph
    forall lb. Label lb => NSGraph lb -> NSGraph lb -> NSGraph lb
    merge ([RDFGraph] -> [RDFGraph]
    forall a. Eq a => [a] -> [a]
    nub [RDFGraph]
    ante)]
              | [RDFVarBinding]
    vs <- [[RDFVarBinding]]
    varn
              , let ante :: [RDFGraph]
    ante = [RDFVarBinding] -> RDFArcSet -> [RDFGraph]
    querySubsBlank [RDFVarBinding]
    vs (GraphClosure RDFLabel -> RDFArcSet
    forall lb. GraphClosure lb -> ArcSet lb
    ruleAnt GraphClosure RDFLabel
    grc) ]

    ------------------------------------------------------------
    --  RDF graph query and substitution support functions
    ------------------------------------------------------------

    queryFind :: RDFArcSet -> RDFGraph -> [RDFVarBinding]
    queryFind :: RDFArcSet -> RDFGraph -> [RDFVarBinding]
    queryFind RDFArcSet
    qas = RDFGraph -> RDFGraph -> [RDFVarBinding]
    rdfQueryFind (RDFArcSet -> RDFGraph
    toRDFGraph RDFArcSet
    qas)

    queryBack :: RDFArcSet -> RDFGraph -> [[RDFVarBinding]]
    queryBack :: RDFArcSet -> RDFGraph -> [[RDFVarBinding]]
    queryBack RDFArcSet
    qas = RDFGraph -> RDFGraph -> [[RDFVarBinding]]
    rdfQueryBack (RDFArcSet -> RDFGraph
    toRDFGraph RDFArcSet
    qas)

    querySubs :: [RDFVarBinding] -> RDFArcSet -> [RDFGraph]
    querySubs :: [RDFVarBinding] -> RDFArcSet -> [RDFGraph]
    querySubs [RDFVarBinding]
    vars = [RDFVarBinding] -> RDFGraph -> [RDFGraph]
    rdfQuerySubs [RDFVarBinding]
    vars (RDFGraph -> [RDFGraph])
    -> (RDFArcSet -> RDFGraph) -> RDFArcSet -> [RDFGraph]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . RDFArcSet -> RDFGraph
    toRDFGraph

    querySubsBlank :: [RDFVarBinding] -> RDFArcSet -> [RDFGraph]
    querySubsBlank :: [RDFVarBinding] -> RDFArcSet -> [RDFGraph]
    querySubsBlank [RDFVarBinding]
    vars = [RDFVarBinding] -> RDFGraph -> [RDFGraph]
    rdfQuerySubsBlank [RDFVarBinding]
    vars (RDFGraph -> [RDFGraph])
    -> (RDFArcSet -> RDFGraph) -> RDFArcSet -> [RDFGraph]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . RDFArcSet -> RDFGraph
    toRDFGraph

    ------------------------------------------------------------
    --  Method for creating an RDF formula value from N3 text
    ------------------------------------------------------------

    mkPrefix :: Namespace -> B.Builder
    mkPrefix :: Namespace -> Builder
    mkPrefix = Namespace -> Builder
    namespaceToBuilder

    prefixRDF :: B.Builder
    prefixRDF :: Builder
    prefixRDF =
      [Builder] -> Builder
    forall a. Monoid a => [a] -> a
    mconcat
      [ Namespace -> Builder
    mkPrefix Namespace
    namespaceRDF
      , Namespace -> Builder
    mkPrefix Namespace
    namespaceRDFS
        ]

    -- |Helper function to parse a string containing Notation3
    --  and return the corresponding RDFGraph value.
    --
    makeRDFGraphFromN3Builder :: B.Builder -> RDFGraph
    makeRDFGraphFromN3Builder :: Builder -> RDFGraph
    makeRDFGraphFromN3Builder Builder
    b =
      let t :: Text
    t = Builder -> Text
    B.toLazyText (Builder
    prefixRDF Builder -> Builder -> Builder
    forall a. Monoid a => a -> a -> a
    `mappend` Builder
    b)
      in case Text -> Maybe QName -> ParseResult
    parseN3 Text
    t Maybe QName
    forall a. Maybe a
    Nothing of
        Left  String
    msg -> String -> RDFGraph
    forall a. HasCallStack => String -> a
    error String
    msg
        Right RDFGraph
    gr  -> RDFGraph
    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
        -> RDFFormula
    makeRDFFormula :: Namespace -> LName -> Builder -> Formula RDFGraph
    makeRDFFormula Namespace
    scope LName
    local Builder
    gr =
      Formula
        { formName :: ScopedName
    formName = Namespace -> LName -> ScopedName
    makeNSScopedName Namespace
    scope LName
    local
        , formExpr :: RDFGraph
    formExpr = Builder -> RDFGraph
    makeRDFGraphFromN3Builder Builder
    gr
        }

    ------------------------------------------------------------
    --  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'
        --
        -> RDFRule
    makeRDFClosureRule :: ScopedName
    -> [RDFGraph]
    -> RDFGraph
    -> VarBindingModify RDFLabel RDFLabel
    -> Rule RDFGraph
    makeRDFClosureRule ScopedName
    sname [RDFGraph]
    antgrs RDFGraph
    congr VarBindingModify RDFLabel RDFLabel
    vmod = GraphClosure RDFLabel -> Rule RDFGraph
    makeGraphClosureRule
        GraphClosure
            { nameGraphRule :: ScopedName
    nameGraphRule = ScopedName
    sname
            , ruleAnt :: RDFArcSet
    ruleAnt       = [RDFArcSet] -> RDFArcSet
    forall (f :: * -> *) a. (Foldable f, Ord a) => f (Set a) -> Set a
    S.unions ([RDFArcSet] -> RDFArcSet) -> [RDFArcSet] -> RDFArcSet
    forall a b. (a -> b) -> a -> b
    $ (RDFGraph -> RDFArcSet) -> [RDFGraph] -> [RDFArcSet]
    forall a b. (a -> b) -> [a] -> [b]
    map RDFGraph -> RDFArcSet
    forall (lg :: * -> *) lb. LDGraph lg lb => lg lb -> ArcSet lb
    getArcs [RDFGraph]
    antgrs
            , ruleCon :: RDFArcSet
    ruleCon       = RDFGraph -> RDFArcSet
    forall (lg :: * -> *) lb. LDGraph lg lb => lg lb -> ArcSet lb
    getArcs RDFGraph
    congr
            , ruleModify :: VarBindingModify RDFLabel RDFLabel
    ruleModify    = VarBindingModify RDFLabel RDFLabel
    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'.
        -> RDFRule
    makeN3ClosureRule :: Namespace
    -> LName
    -> Builder
    -> Builder
    -> VarBindingModify RDFLabel RDFLabel
    -> Rule RDFGraph
    makeN3ClosureRule Namespace
    scope LName
    local Builder
    ant Builder
    con =
        ScopedName
    -> [RDFGraph]
    -> RDFGraph
    -> VarBindingModify RDFLabel RDFLabel
    -> Rule RDFGraph
    makeRDFClosureRule (Namespace -> LName -> ScopedName
    makeNSScopedName Namespace
    scope LName
    local) [RDFGraph
    antgr] RDFGraph
    congr
        where
            antgr :: RDFGraph
    antgr = Builder -> RDFGraph
    makeRDFGraphFromN3Builder Builder
    ant
            congr :: RDFGraph
    congr = Builder -> RDFGraph
    makeRDFGraphFromN3Builder Builder
    con

    -- |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.
        -> RDFRule
    makeN3ClosureSimpleRule :: Namespace -> LName -> Builder -> Builder -> Rule RDFGraph
    makeN3ClosureSimpleRule Namespace
    scope LName
    local Builder
    ant Builder
    con =
        Namespace
    -> LName
    -> Builder
    -> Builder
    -> VarBindingModify RDFLabel RDFLabel
    -> Rule RDFGraph
    makeN3ClosureRule Namespace
    scope LName
    local Builder
    ant Builder
    con VarBindingModify RDFLabel RDFLabel
    forall a b. VarBindingModify a b
    varBindingId

    -- |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@).
        -> RDFRule
    makeN3ClosureModifyRule :: Namespace
    -> LName
    -> Builder
    -> Builder
    -> VarBindingModify RDFLabel RDFLabel
    -> VarBindingModify RDFLabel RDFLabel
    -> Rule RDFGraph
    makeN3ClosureModifyRule Namespace
    scope LName
    local Builder
    ant Builder
    con VarBindingModify RDFLabel RDFLabel
    vflt VarBindingModify RDFLabel RDFLabel
    vmod =
        Namespace
    -> LName
    -> Builder
    -> Builder
    -> VarBindingModify RDFLabel RDFLabel
    -> Rule RDFGraph
    makeN3ClosureRule Namespace
    scope LName
    local Builder
    ant Builder
    con VarBindingModify RDFLabel RDFLabel
    modc
        where
            modc :: VarBindingModify RDFLabel RDFLabel
    modc  = VarBindingModify RDFLabel RDFLabel
    -> Maybe (VarBindingModify RDFLabel RDFLabel)
    -> VarBindingModify RDFLabel RDFLabel
    forall a. a -> Maybe a -> a
    fromMaybe VarBindingModify RDFLabel RDFLabel
    forall a b. VarBindingModify a b
    varBindingId (Maybe (VarBindingModify RDFLabel RDFLabel)
     -> VarBindingModify RDFLabel RDFLabel)
    -> Maybe (VarBindingModify RDFLabel RDFLabel)
    -> VarBindingModify RDFLabel RDFLabel
    forall a b. (a -> b) -> a -> b
    $ VarBindingModify RDFLabel RDFLabel
    -> VarBindingModify RDFLabel RDFLabel
    -> Maybe (VarBindingModify RDFLabel RDFLabel)
    forall a b.
    Eq a =>
    VarBindingModify a b
    -> VarBindingModify a b -> Maybe (VarBindingModify a b)
    vbmCompose VarBindingModify RDFLabel RDFLabel
    vmod VarBindingModify RDFLabel RDFLabel
    vflt

    {-
        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').
        -> RDFRule
    makeN3ClosureAllocatorRule :: Namespace
    -> LName
    -> Builder
    -> Builder
    -> VarBindingModify RDFLabel RDFLabel
    -> ([RDFLabel] -> VarBindingModify RDFLabel RDFLabel)
    -> Rule RDFGraph
    makeN3ClosureAllocatorRule Namespace
    scope LName
    local Builder
    ant Builder
    con VarBindingModify RDFLabel RDFLabel
    vflt [RDFLabel] -> VarBindingModify RDFLabel RDFLabel
    aloc =
        ScopedName
    -> [RDFGraph]
    -> RDFGraph
    -> VarBindingModify RDFLabel RDFLabel
    -> Rule RDFGraph
    makeRDFClosureRule (Namespace -> LName -> ScopedName
    makeNSScopedName Namespace
    scope LName
    local) [RDFGraph
    antgr] RDFGraph
    congr VarBindingModify RDFLabel RDFLabel
    modc
        where
            antgr :: RDFGraph
    antgr = Builder -> RDFGraph
    makeRDFGraphFromN3Builder Builder
    ant
            congr :: RDFGraph
    congr = Builder -> RDFGraph
    makeRDFGraphFromN3Builder Builder
    con
            vmod :: VarBindingModify RDFLabel RDFLabel
    vmod  = [RDFLabel] -> VarBindingModify RDFLabel RDFLabel
    aloc ([RDFLabel] -> VarBindingModify RDFLabel RDFLabel)
    -> [RDFLabel] -> VarBindingModify RDFLabel RDFLabel
    forall a b. (a -> b) -> a -> b
    $ Set RDFLabel -> [RDFLabel]
    forall a. Set a -> [a]
    S.toList ((RDFLabel -> Bool) -> RDFGraph -> Set RDFLabel
    forall lb. Label lb => (lb -> Bool) -> NSGraph lb -> Set lb
    allLabels RDFLabel -> Bool
    forall lb. Label lb => lb -> Bool
    labelIsVar RDFGraph
    antgr)
            modc :: VarBindingModify RDFLabel RDFLabel
    modc  = VarBindingModify RDFLabel RDFLabel
    -> Maybe (VarBindingModify RDFLabel RDFLabel)
    -> VarBindingModify RDFLabel RDFLabel
    forall a. a -> Maybe a -> a
    fromMaybe VarBindingModify RDFLabel RDFLabel
    forall a b. VarBindingModify a b
    varBindingId (Maybe (VarBindingModify RDFLabel RDFLabel)
     -> VarBindingModify RDFLabel RDFLabel)
    -> Maybe (VarBindingModify RDFLabel RDFLabel)
    -> VarBindingModify RDFLabel RDFLabel
    forall a b. (a -> b) -> a -> b
    $ VarBindingModify RDFLabel RDFLabel
    -> VarBindingModify RDFLabel RDFLabel
    -> Maybe (VarBindingModify RDFLabel RDFLabel)
    forall a b.
    Eq a =>
    VarBindingModify a b
    -> VarBindingModify a b -> Maybe (VarBindingModify a b)
    vbmCompose VarBindingModify RDFLabel RDFLabel
    vmod VarBindingModify RDFLabel RDFLabel
    vflt

    ------------------------------------------------------------
    --  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]
        -> RDFVarBindingModify
    makeNodeAllocTo :: RDFLabel
    -> RDFLabel -> [RDFLabel] -> VarBindingModify RDFLabel RDFLabel
    makeNodeAllocTo RDFLabel
    bindvar RDFLabel
    alocvar [RDFLabel]
    exbnode = VarBindingModify
            { vbmName :: ScopedName
    vbmName   = LName -> ScopedName
    swishName LName
    "makeNodeAllocTo"
            , vbmApply :: [RDFVarBinding] -> [RDFVarBinding]
    vbmApply  = RDFLabel
    -> RDFLabel -> [RDFLabel] -> [RDFVarBinding] -> [RDFVarBinding]
    applyNodeAllocTo RDFLabel
    bindvar RDFLabel
    alocvar [RDFLabel]
    exbnode
            , vbmVocab :: [RDFLabel]
    vbmVocab  = [RDFLabel
    alocvar,RDFLabel
    bindvar]
            , vbmUsage :: [[RDFLabel]]
    vbmUsage  = [[RDFLabel
    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]
    applyNodeAllocTo :: RDFLabel
    -> RDFLabel -> [RDFLabel] -> [RDFVarBinding] -> [RDFVarBinding]
    applyNodeAllocTo RDFLabel
    bindvar RDFLabel
    alocvar [RDFLabel]
    exbnode [RDFVarBinding]
    vars =
        let
            app :: VarBinding a a -> a -> a
    app       = VarBinding a a -> a -> a
    forall a. VarBinding a a -> a -> a
    applyVarBinding
            alocnodes :: [(RDFLabel, RDFLabel)]
    alocnodes = [RDFLabel] -> [RDFLabel] -> [(RDFLabel, RDFLabel)]
    forall a b. [a] -> [b] -> [(a, b)]
    zip ([RDFLabel] -> [RDFLabel]
    forall a. Eq a => [a] -> [a]
    nub ([RDFLabel] -> [RDFLabel]) -> [RDFLabel] -> [RDFLabel]
    forall a b. (a -> b) -> a -> b
    $ [RDFLabel -> RDFLabel] -> RDFLabel -> [RDFLabel]
    forall a b. [a -> b] -> a -> [b]
    flist ((RDFVarBinding -> RDFLabel -> RDFLabel)
    -> [RDFVarBinding] -> [RDFLabel -> RDFLabel]
    forall a b. (a -> b) -> [a] -> [b]
    map RDFVarBinding -> RDFLabel -> RDFLabel
    forall a. VarBinding a a -> a -> a
    app [RDFVarBinding]
    vars) RDFLabel
    alocvar)
                            (RDFLabel -> [RDFLabel] -> [RDFLabel]
    forall lb. Label lb => lb -> [lb] -> [lb]
    newNodes (RDFLabel -> RDFLabel
    makeBlank RDFLabel
    bindvar) [RDFLabel]
    exbnode)
            newvb :: RDFVarBinding -> RDFVarBinding
    newvb RDFVarBinding
    var = RDFVarBinding -> RDFVarBinding -> RDFVarBinding
    forall a b.
    (Ord a, Ord b) =>
    VarBinding a b -> VarBinding a b -> VarBinding a b
    joinVarBindings
                ( [(RDFLabel, RDFLabel)] -> RDFVarBinding
    forall a b. (Ord a, Ord b) => [(a, b)] -> VarBinding a b
    makeVarBinding ([(RDFLabel, RDFLabel)] -> RDFVarBinding)
    -> [(RDFLabel, RDFLabel)] -> RDFVarBinding
    forall a b. (a -> b) -> a -> b
    $ [[(RDFLabel, RDFLabel)]] -> [(RDFLabel, RDFLabel)]
    forall a. HasCallStack => [a] -> a
    head
                  [ [(RDFLabel
    bindvar,RDFLabel
    b)] | (RDFLabel
    v,RDFLabel
    b) <- [(RDFLabel, RDFLabel)]
    alocnodes, RDFVarBinding -> RDFLabel -> RDFLabel
    forall a. VarBinding a a -> a -> a
    app RDFVarBinding
    var RDFLabel
    alocvar RDFLabel -> RDFLabel -> Bool
    forall a. Eq a => a -> a -> Bool
    == RDFLabel
    v ] )
                RDFVarBinding
    var
        in
            (RDFVarBinding -> RDFVarBinding)
    -> [RDFVarBinding] -> [RDFVarBinding]
    forall a b. (a -> b) -> [a] -> [b]
    map RDFVarBinding -> RDFVarBinding
    newvb [RDFVarBinding]
    vars

    --------------------------------------------------------------------------------
    --
    --  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
    --
    --------------------------------------------------------------------------------