Claude attempts to do a routine rename #1
@ -26,9 +26,9 @@ Megaparsec-based parser that converts Datalog text into an AST:
|
|||||||
- `Statement` - Fact, Rule (with `Head` and body literals), or Query
|
- `Statement` - Fact, Rule (with `Head` and body literals), or Query
|
||||||
- Entry points: `parseDatalog`, `parseDatalogFile`
|
- Entry points: `parseDatalog`, `parseDatalogFile`
|
||||||
|
|
||||||
### Evaluation Engine (`src/Datalog/NaiveDatabase.hs`)
|
### Evaluation Engine (`src/Datalog/InMemoryDB.hs`)
|
||||||
Naive evaluation database storing relations and rules:
|
In-memory database storing relations and rules:
|
||||||
- `NaiveDatabase` - Contains `relations` map and `constants` set (Herbrand universe)
|
- `InMemoryDB` - Contains `relations` map and `constants` set (Herbrand universe)
|
||||||
- `Relation` - Name, arity, tuples (facts), and associated rules
|
- `Relation` - Name, arity, tuples (facts), and associated rules
|
||||||
- `RelationRule` - Head variables and body constraints
|
- `RelationRule` - Head variables and body constraints
|
||||||
- Key functions: `withFacts`, `withFactsAndRules` for building databases
|
- Key functions: `withFacts`, `withFactsAndRules` for building databases
|
||||||
|
|||||||
@ -82,16 +82,17 @@ test-suite haskell-exps-test
|
|||||||
Test.SimpleParserSpec,
|
Test.SimpleParserSpec,
|
||||||
Test.ArithmeticParserSpec,
|
Test.ArithmeticParserSpec,
|
||||||
Test.Datalog.DatalogParserSpec,
|
Test.Datalog.DatalogParserSpec,
|
||||||
Test.Datalog.NaiveDatabaseSpec
|
Test.Datalog.InMemoryDBSpec
|
||||||
|
|
||||||
library langfeatures
|
library langfeatures
|
||||||
|
default-language: Haskell2010
|
||||||
build-depends: base, containers, megaparsec, parser-combinators, text
|
build-depends: base, containers, megaparsec, parser-combinators, text
|
||||||
hs-source-dirs: src
|
hs-source-dirs: src
|
||||||
exposed-modules: Ologs
|
exposed-modules: Ologs
|
||||||
SimpleParser
|
SimpleParser
|
||||||
ArithmeticParser
|
ArithmeticParser
|
||||||
Datalog.DatalogParser
|
Datalog.DatalogParser
|
||||||
Datalog.NaiveDatabase
|
Datalog.InMemoryDB
|
||||||
Datalog.Rules
|
Datalog.Rules
|
||||||
Datalog.DatalogDB
|
Datalog.DatalogDB
|
||||||
ghc-options: -Wall
|
ghc-options: -Wall
|
||||||
@ -99,8 +100,8 @@ library langfeatures
|
|||||||
OverloadedStrings
|
OverloadedStrings
|
||||||
|
|
||||||
executable haskell-experiments
|
executable haskell-experiments
|
||||||
|
default-language: Haskell2010
|
||||||
build-depends: base, containers
|
build-depends: base, containers
|
||||||
main-is: Main.hs
|
main-is: Main.hs
|
||||||
hs-source-dirs: src
|
hs-source-dirs: src
|
||||||
default-language: Haskell2010
|
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
# NaiveDatabase.hs Summary
|
# InMemoryDB.hs Summary
|
||||||
|
|
||||||
This module implements a naive Datalog database with support for facts, rules, and queries.
|
This module implements an in-memory Datalog database with support for facts, rules, and queries.
|
||||||
|
|
||||||
## Data Types
|
## Data Types
|
||||||
|
|
||||||
@ -9,7 +9,7 @@ A simple algebraic data type representing values in the database.
|
|||||||
- `ValueInt Int` - Integer value
|
- `ValueInt Int` - Integer value
|
||||||
- `ValueSymbol String` - Symbolic value
|
- `ValueSymbol String` - Symbolic value
|
||||||
|
|
||||||
### NaiveDatabase
|
### InMemoryDB
|
||||||
The main database structure containing:
|
The main database structure containing:
|
||||||
- `relations :: Map RelationId Relation` - Map of relation names to relations
|
- `relations :: Map RelationId Relation` - Map of relation names to relations
|
||||||
- `constants :: Set Constant` - The Herbrand universe (all constants in the database)
|
- `constants :: Set Constant` - The Herbrand universe (all constants in the database)
|
||||||
@ -46,9 +46,9 @@ Context maintained while processing rules:
|
|||||||
- `__relation :: Relation` - The relation being defined
|
- `__relation :: Relation` - The relation being defined
|
||||||
- `_headVariables :: [RuleElement]` - Variables collected from head and body
|
- `_headVariables :: [RuleElement]` - Variables collected from head and body
|
||||||
- `_bodyConstraints :: [BodyConstraint]` - Constraints from rule body
|
- `_bodyConstraints :: [BodyConstraint]` - Constraints from rule body
|
||||||
- `_db :: NaiveDatabase` - Current database state
|
- `_db :: InMemoryDB` - Current database state
|
||||||
|
|
||||||
### NaiveDatabaseException
|
### InMemoryDBException
|
||||||
Exception types for error handling:
|
Exception types for error handling:
|
||||||
- `CannotParseStatementException` - Failed to parse Datalog text
|
- `CannotParseStatementException` - Failed to parse Datalog text
|
||||||
- `NonFactException` - Expected a fact but got another statement type
|
- `NonFactException` - Expected a fact but got another statement type
|
||||||
@ -1,10 +1,10 @@
|
|||||||
digraph NaiveDatabase {
|
digraph InMemoryDB {
|
||||||
rankdir=TB;
|
rankdir=TB;
|
||||||
node [shape=record, fontname="Helvetica", fontsize=10];
|
node [shape=record, fontname="Helvetica", fontsize=10];
|
||||||
edge [fontname="Helvetica", fontsize=9];
|
edge [fontname="Helvetica", fontsize=9];
|
||||||
|
|
||||||
// Main database
|
// Main database
|
||||||
NaiveDatabase [label="{NaiveDatabase|relations : Map RelationId Relation\lconstants : Set Constant\l}"];
|
InMemoryDB [label="{InMemoryDB|relations : Map RelationId Relation\lconstants : Set Constant\l}"];
|
||||||
|
|
||||||
// Core data types
|
// Core data types
|
||||||
Relation [label="{Relation|_name : Text\l_arity : Int\l_tuples : Set [Constant]\l_rules : [RelationRule]\l}"];
|
Relation [label="{Relation|_name : Text\l_arity : Int\l_tuples : Set [Constant]\l_rules : [RelationRule]\l}"];
|
||||||
@ -18,7 +18,7 @@ digraph NaiveDatabase {
|
|||||||
|
|
||||||
BodyConstraint [label="{BodyConstraint|_relation : Relation\l_elements : [ConstraintElement]\l}"];
|
BodyConstraint [label="{BodyConstraint|_relation : Relation\l_elements : [ConstraintElement]\l}"];
|
||||||
|
|
||||||
RuleContext [label="{RuleContext|__relation : Relation\l_headVariables : [RuleElement]\l_bodyConstraints : [BodyConstraint]\l_db : NaiveDatabase\l}"];
|
RuleContext [label="{RuleContext|__relation : Relation\l_headVariables : [RuleElement]\l_bodyConstraints : [BodyConstraint]\l_db : InMemoryDB\l}"];
|
||||||
|
|
||||||
// Type aliases (shown as notes)
|
// Type aliases (shown as notes)
|
||||||
TypeAliases [shape=note, label="Type Aliases\l\lConstant = Term\lRelationId = Text\l"];
|
TypeAliases [shape=note, label="Type Aliases\l\lConstant = Term\lRelationId = Text\l"];
|
||||||
@ -27,10 +27,10 @@ digraph NaiveDatabase {
|
|||||||
Value [label="{Value|ValueInt Int\l| ValueSymbol String\l}"];
|
Value [label="{Value|ValueInt Int\l| ValueSymbol String\l}"];
|
||||||
|
|
||||||
// Exception type
|
// Exception type
|
||||||
NaiveDatabaseException [label="{NaiveDatabaseException|CannotParseStatementException\l| NonFactException\l| NonRuleException\l| NonQueryException\l| BadArityException\l| VariableLookupException\l| UnexpectedConstantException\l}"];
|
InMemoryDBException [label="{InMemoryDBException|CannotParseStatementException\l| NonFactException\l| NonRuleException\l| NonQueryException\l| BadArityException\l| VariableLookupException\l| UnexpectedConstantException\l}"];
|
||||||
|
|
||||||
// Relationships
|
// Relationships
|
||||||
NaiveDatabase -> Relation [label="contains *", style=solid];
|
InMemoryDB -> Relation [label="contains *", style=solid];
|
||||||
Relation -> RelationRule [label="has *", style=solid];
|
Relation -> RelationRule [label="has *", style=solid];
|
||||||
RelationRule -> Relation [label="references *", style=dashed];
|
RelationRule -> Relation [label="references *", style=dashed];
|
||||||
RelationRule -> RuleElement [label="contains *", style=solid];
|
RelationRule -> RuleElement [label="contains *", style=solid];
|
||||||
@ -41,14 +41,14 @@ digraph NaiveDatabase {
|
|||||||
RuleContext -> Relation [label="references", style=dashed];
|
RuleContext -> Relation [label="references", style=dashed];
|
||||||
RuleContext -> RuleElement [label="contains *", style=solid];
|
RuleContext -> RuleElement [label="contains *", style=solid];
|
||||||
RuleContext -> BodyConstraint [label="contains *", style=solid];
|
RuleContext -> BodyConstraint [label="contains *", style=solid];
|
||||||
RuleContext -> NaiveDatabase [label="references", style=dashed];
|
RuleContext -> InMemoryDB [label="references", style=dashed];
|
||||||
|
|
||||||
// Grouping
|
// Grouping
|
||||||
subgraph cluster_core {
|
subgraph cluster_core {
|
||||||
label="Core Types";
|
label="Core Types";
|
||||||
style=rounded;
|
style=rounded;
|
||||||
color=blue;
|
color=blue;
|
||||||
NaiveDatabase; Relation; RelationRule; RuleElement;
|
InMemoryDB; Relation; RelationRule; RuleElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
subgraph cluster_processing {
|
subgraph cluster_processing {
|
||||||
@ -62,6 +62,6 @@ digraph NaiveDatabase {
|
|||||||
label="Other";
|
label="Other";
|
||||||
style=rounded;
|
style=rounded;
|
||||||
color=gray;
|
color=gray;
|
||||||
Value; NaiveDatabaseException; TypeAliases;
|
Value; InMemoryDBException; TypeAliases;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6,7 +6,7 @@
|
|||||||
{-# LANGUAGE InstanceSigs #-}
|
{-# LANGUAGE InstanceSigs #-}
|
||||||
{-# LANGUAGE BlockArguments #-}
|
{-# LANGUAGE BlockArguments #-}
|
||||||
|
|
||||||
module Datalog.NaiveDatabase where
|
module Datalog.InMemoryDB where
|
||||||
|
|
||||||
import Control.Exception.Base
|
import Control.Exception.Base
|
||||||
import Data.Map (Map)
|
import Data.Map (Map)
|
||||||
@ -18,30 +18,30 @@ import Datalog.DatalogParser (Literal (..), Statement (..), parseDatalog)
|
|||||||
import Datalog.Rules
|
import Datalog.Rules
|
||||||
import Datalog.DatalogDB
|
import Datalog.DatalogDB
|
||||||
|
|
||||||
data NaiveDatabase = NaiveDatabase
|
data InMemoryDB = InMemoryDB
|
||||||
{ relations :: Map RelationId Relation
|
{ relations :: Map RelationId Relation
|
||||||
, constants :: Set Constant
|
, constants :: Set Constant
|
||||||
} deriving (Show, Eq)
|
} deriving (Show, Eq)
|
||||||
|
|
||||||
|
|
||||||
instance DatalogDB NaiveDatabase where
|
instance DatalogDB InMemoryDB where
|
||||||
emptyDB :: NaiveDatabase
|
emptyDB :: InMemoryDB
|
||||||
emptyDB = NaiveDatabase
|
emptyDB = InMemoryDB
|
||||||
{ relations = Map.empty
|
{ relations = Map.empty
|
||||||
, constants = Set.empty -- the Herbrand universe
|
, constants = Set.empty -- the Herbrand universe
|
||||||
}
|
}
|
||||||
|
|
||||||
lookupRelation :: NaiveDatabase -> Text -> Maybe Relation
|
lookupRelation :: InMemoryDB -> Text -> Maybe Relation
|
||||||
lookupRelation db relationName =
|
lookupRelation db relationName =
|
||||||
Map.lookup relationName $ relations db
|
Map.lookup relationName $ relations db
|
||||||
|
|
||||||
insertRelation :: NaiveDatabase -> Relation -> NaiveDatabase
|
insertRelation :: InMemoryDB -> Relation -> InMemoryDB
|
||||||
insertRelation db relation =
|
insertRelation db relation =
|
||||||
db {
|
db {
|
||||||
relations = Map.insert (_name relation) relation (relations db)
|
relations = Map.insert (_name relation) relation (relations db)
|
||||||
}
|
}
|
||||||
|
|
||||||
addConstants :: NaiveDatabase -> Set Constant -> NaiveDatabase
|
addConstants :: InMemoryDB -> Set Constant -> InMemoryDB
|
||||||
addConstants db newConstants =
|
addConstants db newConstants =
|
||||||
db {
|
db {
|
||||||
constants = Set.union newConstants (constants db)
|
constants = Set.union newConstants (constants db)
|
||||||
@ -78,7 +78,7 @@ withFacts =
|
|||||||
Right otherStatement -> throw $ NonFactException factText otherStatement
|
Right otherStatement -> throw $ NonFactException factText otherStatement
|
||||||
Left ex -> throw $ CannotParseStatementException factText ex
|
Left ex -> throw $ CannotParseStatementException factText ex
|
||||||
|
|
||||||
withFactsAndRules :: [Text] -> [Text] -> NaiveDatabase
|
withFactsAndRules :: [Text] -> [Text] -> InMemoryDB
|
||||||
withFactsAndRules facts = foldr (addRule . extractRule) (withFacts facts)
|
withFactsAndRules facts = foldr (addRule . extractRule) (withFacts facts)
|
||||||
|
|
||||||
query :: forall db . (DatalogDB db) => db -> Text -> Text
|
query :: forall db . (DatalogDB db) => db -> Text -> Text
|
||||||
@ -87,4 +87,3 @@ query db qText =
|
|||||||
Right (Query texts literals) -> "#NYI"
|
Right (Query texts literals) -> "#NYI"
|
||||||
Right otherStatement -> throw $ NonQueryException qText otherStatement
|
Right otherStatement -> throw $ NonQueryException qText otherStatement
|
||||||
Left ex -> throw $ CannotParseStatementException qText ex
|
Left ex -> throw $ CannotParseStatementException qText ex
|
||||||
|
|
||||||
@ -5,7 +5,7 @@ import qualified Test.OlogsSpec as Ologs
|
|||||||
import qualified Test.SimpleParserSpec as SimpleParserSpec
|
import qualified Test.SimpleParserSpec as SimpleParserSpec
|
||||||
import qualified Test.ArithmeticParserSpec as ArithmeticParserSpec
|
import qualified Test.ArithmeticParserSpec as ArithmeticParserSpec
|
||||||
import qualified Test.Datalog.DatalogParserSpec as DatalogParserSpec
|
import qualified Test.Datalog.DatalogParserSpec as DatalogParserSpec
|
||||||
import qualified Test.Datalog.NaiveDatabaseSpec as NaiveDatabaseSpec
|
import qualified Test.Datalog.InMemoryDBSpec as InMemoryDBSpec
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = hspec $ do
|
main = hspec $ do
|
||||||
@ -13,5 +13,5 @@ main = hspec $ do
|
|||||||
describe "SimpleParser" SimpleParserSpec.spec
|
describe "SimpleParser" SimpleParserSpec.spec
|
||||||
describe "ArithmeticParser" ArithmeticParserSpec.spec
|
describe "ArithmeticParser" ArithmeticParserSpec.spec
|
||||||
describe "DatalogParser" DatalogParserSpec.spec
|
describe "DatalogParser" DatalogParserSpec.spec
|
||||||
describe "NaiveDatabase" NaiveDatabaseSpec.spec
|
describe "InMemoryDB" InMemoryDBSpec.spec
|
||||||
|
|
||||||
|
|||||||
@ -12,22 +12,22 @@
|
|||||||
{-# LANGUAGE NoMonomorphismRestriction #-}
|
{-# LANGUAGE NoMonomorphismRestriction #-}
|
||||||
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
|
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
|
||||||
|
|
||||||
module Test.Datalog.NaiveDatabaseSpec where
|
module Test.Datalog.InMemoryDBSpec where
|
||||||
|
|
||||||
import Data.Map qualified as Map
|
import Data.Map qualified as Map
|
||||||
import Data.Set qualified as Set
|
import Data.Set qualified as Set
|
||||||
import Datalog.DatalogParser
|
import Datalog.DatalogParser
|
||||||
import Datalog.NaiveDatabase
|
import Datalog.InMemoryDB
|
||||||
import Datalog.NaiveDatabase qualified as NaiveDatabase
|
import Datalog.InMemoryDB qualified as InMemoryDB
|
||||||
import Test.Hspec
|
import Test.Hspec
|
||||||
import Datalog.DatalogDB
|
import Datalog.DatalogDB
|
||||||
|
|
||||||
spec :: Spec
|
spec :: Spec
|
||||||
spec = do
|
spec = do
|
||||||
describe "NaiveDatabase operations" do
|
describe "InMemoryDB operations" do
|
||||||
it "can ingest facts into relations & a universe" $ do
|
it "can ingest facts into relations & a universe" $ do
|
||||||
let db =
|
let db =
|
||||||
NaiveDatabase.withFacts
|
InMemoryDB.withFacts
|
||||||
[ "parent(\"alice\", \"bob\")."
|
[ "parent(\"alice\", \"bob\")."
|
||||||
, "parent(\"bob\", \"carol\")."
|
, "parent(\"bob\", \"carol\")."
|
||||||
]
|
]
|
||||||
@ -42,7 +42,7 @@ spec = do
|
|||||||
]
|
]
|
||||||
it "can ingest facts and rules" do
|
it "can ingest facts and rules" do
|
||||||
let db =
|
let db =
|
||||||
NaiveDatabase.withFactsAndRules
|
InMemoryDB.withFactsAndRules
|
||||||
[ "parent(\"alice\", \"bob\")."
|
[ "parent(\"alice\", \"bob\")."
|
||||||
, "parent(\"bob\", \"carol\")."
|
, "parent(\"bob\", \"carol\")."
|
||||||
]
|
]
|
||||||
@ -105,7 +105,7 @@ spec = do
|
|||||||
|
|
||||||
it "can ingest facts and rules with constants" do
|
it "can ingest facts and rules with constants" do
|
||||||
let db =
|
let db =
|
||||||
NaiveDatabase.withFactsAndRules
|
InMemoryDB.withFactsAndRules
|
||||||
[]
|
[]
|
||||||
["ancestor(X,\"patriarch\") :- ."]
|
["ancestor(X,\"patriarch\") :- ."]
|
||||||
ancestorRule =
|
ancestorRule =
|
||||||
@ -128,7 +128,7 @@ spec = do
|
|||||||
|
|
||||||
it "can ingest facts and rules with duplicate head entries" do
|
it "can ingest facts and rules with duplicate head entries" do
|
||||||
let db =
|
let db =
|
||||||
NaiveDatabase.withFactsAndRules
|
InMemoryDB.withFactsAndRules
|
||||||
[]
|
[]
|
||||||
["equivalent(Q,Q) :- ."]
|
["equivalent(Q,Q) :- ."]
|
||||||
equivalentRule =
|
equivalentRule =
|
||||||
@ -151,7 +151,7 @@ spec = do
|
|||||||
|
|
||||||
it "can ingest facts and rules with duplicate head entries" do
|
it "can ingest facts and rules with duplicate head entries" do
|
||||||
let db =
|
let db =
|
||||||
NaiveDatabase.withFactsAndRules
|
InMemoryDB.withFactsAndRules
|
||||||
[]
|
[]
|
||||||
["equivalent(Q,Q) :- ."]
|
["equivalent(Q,Q) :- ."]
|
||||||
rule1 =
|
rule1 =
|
||||||
@ -175,7 +175,7 @@ spec = do
|
|||||||
|
|
||||||
it "can ingest a theory of equivalence relations" do
|
it "can ingest a theory of equivalence relations" do
|
||||||
let db =
|
let db =
|
||||||
NaiveDatabase.withFactsAndRules
|
InMemoryDB.withFactsAndRules
|
||||||
[]
|
[]
|
||||||
[ "equivalent(Q,Q) :- ."
|
[ "equivalent(Q,Q) :- ."
|
||||||
, "equivalent(R,Q) :- equivalent(Q,R)."
|
, "equivalent(R,Q) :- equivalent(Q,R)."
|
||||||
@ -233,8 +233,8 @@ spec = do
|
|||||||
`shouldBe` Set.empty
|
`shouldBe` Set.empty
|
||||||
|
|
||||||
it "can do basic queries" do
|
it "can do basic queries" do
|
||||||
let db :: NaiveDatabase =
|
let db :: InMemoryDB =
|
||||||
NaiveDatabase.withFacts
|
InMemoryDB.withFacts
|
||||||
[ "parent(\"alice\", \"bob\")."
|
[ "parent(\"alice\", \"bob\")."
|
||||||
, "parent(\"bob\", \"carol\")."
|
, "parent(\"bob\", \"carol\")."
|
||||||
]
|
]
|
||||||
Loading…
x
Reference in New Issue
Block a user