Compare commits

..

No commits in common. "3003a928074958478869835dcfd1ad7494621eca" and "85e57325dc3f77223ea9c469068cfce597a9e411" have entirely different histories.

7 changed files with 43 additions and 43 deletions

View File

@ -26,9 +26,9 @@ Megaparsec-based parser that converts Datalog text into an AST:
- `Statement` - Fact, Rule (with `Head` and body literals), or Query
- Entry points: `parseDatalog`, `parseDatalogFile`
### Evaluation Engine (`src/Datalog/InMemoryDB.hs`)
In-memory database storing relations and rules:
- `InMemoryDB` - Contains `relations` map and `constants` set (Herbrand universe)
### Evaluation Engine (`src/Datalog/NaiveDatabase.hs`)
Naive evaluation database storing relations and rules:
- `NaiveDatabase` - Contains `relations` map and `constants` set (Herbrand universe)
- `Relation` - Name, arity, tuples (facts), and associated rules
- `RelationRule` - Head variables and body constraints
- Key functions: `withFacts`, `withFactsAndRules` for building databases

View File

@ -82,17 +82,16 @@ test-suite haskell-exps-test
Test.SimpleParserSpec,
Test.ArithmeticParserSpec,
Test.Datalog.DatalogParserSpec,
Test.Datalog.InMemoryDBSpec
Test.Datalog.NaiveDatabaseSpec
library langfeatures
default-language: Haskell2010
build-depends: base, containers, megaparsec, parser-combinators, text
hs-source-dirs: src
exposed-modules: Ologs
SimpleParser
ArithmeticParser
Datalog.DatalogParser
Datalog.InMemoryDB
Datalog.NaiveDatabase
Datalog.Rules
Datalog.DatalogDB
ghc-options: -Wall
@ -100,8 +99,8 @@ library langfeatures
OverloadedStrings
executable haskell-experiments
default-language: Haskell2010
build-depends: base, containers
main-is: Main.hs
hs-source-dirs: src
default-language: Haskell2010

View File

@ -1,6 +1,6 @@
# InMemoryDB.hs Summary
# NaiveDatabase.hs Summary
This module implements an in-memory Datalog database with support for facts, rules, and queries.
This module implements a naive Datalog database with support for facts, rules, and queries.
## Data Types
@ -9,7 +9,7 @@ A simple algebraic data type representing values in the database.
- `ValueInt Int` - Integer value
- `ValueSymbol String` - Symbolic value
### InMemoryDB
### NaiveDatabase
The main database structure containing:
- `relations :: Map RelationId Relation` - Map of relation names to relations
- `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
- `_headVariables :: [RuleElement]` - Variables collected from head and body
- `_bodyConstraints :: [BodyConstraint]` - Constraints from rule body
- `_db :: InMemoryDB` - Current database state
- `_db :: NaiveDatabase` - Current database state
### InMemoryDBException
### NaiveDatabaseException
Exception types for error handling:
- `CannotParseStatementException` - Failed to parse Datalog text
- `NonFactException` - Expected a fact but got another statement type

View File

@ -1,10 +1,10 @@
digraph InMemoryDB {
digraph NaiveDatabase {
rankdir=TB;
node [shape=record, fontname="Helvetica", fontsize=10];
edge [fontname="Helvetica", fontsize=9];
// Main database
InMemoryDB [label="{InMemoryDB|relations : Map RelationId Relation\lconstants : Set Constant\l}"];
NaiveDatabase [label="{NaiveDatabase|relations : Map RelationId Relation\lconstants : Set Constant\l}"];
// Core data types
Relation [label="{Relation|_name : Text\l_arity : Int\l_tuples : Set [Constant]\l_rules : [RelationRule]\l}"];
@ -18,7 +18,7 @@ digraph InMemoryDB {
BodyConstraint [label="{BodyConstraint|_relation : Relation\l_elements : [ConstraintElement]\l}"];
RuleContext [label="{RuleContext|__relation : Relation\l_headVariables : [RuleElement]\l_bodyConstraints : [BodyConstraint]\l_db : InMemoryDB\l}"];
RuleContext [label="{RuleContext|__relation : Relation\l_headVariables : [RuleElement]\l_bodyConstraints : [BodyConstraint]\l_db : NaiveDatabase\l}"];
// Type aliases (shown as notes)
TypeAliases [shape=note, label="Type Aliases\l\lConstant = Term\lRelationId = Text\l"];
@ -27,10 +27,10 @@ digraph InMemoryDB {
Value [label="{Value|ValueInt Int\l| ValueSymbol String\l}"];
// Exception type
InMemoryDBException [label="{InMemoryDBException|CannotParseStatementException\l| NonFactException\l| NonRuleException\l| NonQueryException\l| BadArityException\l| VariableLookupException\l| UnexpectedConstantException\l}"];
NaiveDatabaseException [label="{NaiveDatabaseException|CannotParseStatementException\l| NonFactException\l| NonRuleException\l| NonQueryException\l| BadArityException\l| VariableLookupException\l| UnexpectedConstantException\l}"];
// Relationships
InMemoryDB -> Relation [label="contains *", style=solid];
NaiveDatabase -> Relation [label="contains *", style=solid];
Relation -> RelationRule [label="has *", style=solid];
RelationRule -> Relation [label="references *", style=dashed];
RelationRule -> RuleElement [label="contains *", style=solid];
@ -41,14 +41,14 @@ digraph InMemoryDB {
RuleContext -> Relation [label="references", style=dashed];
RuleContext -> RuleElement [label="contains *", style=solid];
RuleContext -> BodyConstraint [label="contains *", style=solid];
RuleContext -> InMemoryDB [label="references", style=dashed];
RuleContext -> NaiveDatabase [label="references", style=dashed];
// Grouping
subgraph cluster_core {
label="Core Types";
style=rounded;
color=blue;
InMemoryDB; Relation; RelationRule; RuleElement;
NaiveDatabase; Relation; RelationRule; RuleElement;
}
subgraph cluster_processing {
@ -62,6 +62,6 @@ digraph InMemoryDB {
label="Other";
style=rounded;
color=gray;
Value; InMemoryDBException; TypeAliases;
Value; NaiveDatabaseException; TypeAliases;
}
}

View File

@ -6,7 +6,7 @@
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE BlockArguments #-}
module Datalog.InMemoryDB where
module Datalog.NaiveDatabase where
import Control.Exception.Base
import Data.Map (Map)
@ -18,30 +18,30 @@ import Datalog.DatalogParser (Literal (..), Statement (..), parseDatalog)
import Datalog.Rules
import Datalog.DatalogDB
data InMemoryDB = InMemoryDB
data NaiveDatabase = NaiveDatabase
{ relations :: Map RelationId Relation
, constants :: Set Constant
} deriving (Show, Eq)
instance DatalogDB InMemoryDB where
emptyDB :: InMemoryDB
emptyDB = InMemoryDB
instance DatalogDB NaiveDatabase where
emptyDB :: NaiveDatabase
emptyDB = NaiveDatabase
{ relations = Map.empty
, constants = Set.empty -- the Herbrand universe
}
lookupRelation :: InMemoryDB -> Text -> Maybe Relation
lookupRelation :: NaiveDatabase -> Text -> Maybe Relation
lookupRelation db relationName =
Map.lookup relationName $ relations db
insertRelation :: InMemoryDB -> Relation -> InMemoryDB
insertRelation :: NaiveDatabase -> Relation -> NaiveDatabase
insertRelation db relation =
db {
relations = Map.insert (_name relation) relation (relations db)
}
addConstants :: InMemoryDB -> Set Constant -> InMemoryDB
addConstants :: NaiveDatabase -> Set Constant -> NaiveDatabase
addConstants db newConstants =
db {
constants = Set.union newConstants (constants db)
@ -78,7 +78,7 @@ withFacts =
Right otherStatement -> throw $ NonFactException factText otherStatement
Left ex -> throw $ CannotParseStatementException factText ex
withFactsAndRules :: [Text] -> [Text] -> InMemoryDB
withFactsAndRules :: [Text] -> [Text] -> NaiveDatabase
withFactsAndRules facts = foldr (addRule . extractRule) (withFacts facts)
query :: forall db . (DatalogDB db) => db -> Text -> Text
@ -87,3 +87,4 @@ query db qText =
Right (Query texts literals) -> "#NYI"
Right otherStatement -> throw $ NonQueryException qText otherStatement
Left ex -> throw $ CannotParseStatementException qText ex

View File

@ -5,7 +5,7 @@ import qualified Test.OlogsSpec as Ologs
import qualified Test.SimpleParserSpec as SimpleParserSpec
import qualified Test.ArithmeticParserSpec as ArithmeticParserSpec
import qualified Test.Datalog.DatalogParserSpec as DatalogParserSpec
import qualified Test.Datalog.InMemoryDBSpec as InMemoryDBSpec
import qualified Test.Datalog.NaiveDatabaseSpec as NaiveDatabaseSpec
main :: IO ()
main = hspec $ do
@ -13,5 +13,5 @@ main = hspec $ do
describe "SimpleParser" SimpleParserSpec.spec
describe "ArithmeticParser" ArithmeticParserSpec.spec
describe "DatalogParser" DatalogParserSpec.spec
describe "InMemoryDB" InMemoryDBSpec.spec
describe "NaiveDatabase" NaiveDatabaseSpec.spec

View File

@ -12,22 +12,22 @@
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
module Test.Datalog.InMemoryDBSpec where
module Test.Datalog.NaiveDatabaseSpec where
import Data.Map qualified as Map
import Data.Set qualified as Set
import Datalog.DatalogParser
import Datalog.InMemoryDB
import Datalog.InMemoryDB qualified as InMemoryDB
import Datalog.NaiveDatabase
import Datalog.NaiveDatabase qualified as NaiveDatabase
import Test.Hspec
import Datalog.DatalogDB
spec :: Spec
spec = do
describe "InMemoryDB operations" do
describe "NaiveDatabase operations" do
it "can ingest facts into relations & a universe" $ do
let db =
InMemoryDB.withFacts
NaiveDatabase.withFacts
[ "parent(\"alice\", \"bob\")."
, "parent(\"bob\", \"carol\")."
]
@ -42,7 +42,7 @@ spec = do
]
it "can ingest facts and rules" do
let db =
InMemoryDB.withFactsAndRules
NaiveDatabase.withFactsAndRules
[ "parent(\"alice\", \"bob\")."
, "parent(\"bob\", \"carol\")."
]
@ -105,7 +105,7 @@ spec = do
it "can ingest facts and rules with constants" do
let db =
InMemoryDB.withFactsAndRules
NaiveDatabase.withFactsAndRules
[]
["ancestor(X,\"patriarch\") :- ."]
ancestorRule =
@ -128,7 +128,7 @@ spec = do
it "can ingest facts and rules with duplicate head entries" do
let db =
InMemoryDB.withFactsAndRules
NaiveDatabase.withFactsAndRules
[]
["equivalent(Q,Q) :- ."]
equivalentRule =
@ -151,7 +151,7 @@ spec = do
it "can ingest facts and rules with duplicate head entries" do
let db =
InMemoryDB.withFactsAndRules
NaiveDatabase.withFactsAndRules
[]
["equivalent(Q,Q) :- ."]
rule1 =
@ -175,7 +175,7 @@ spec = do
it "can ingest a theory of equivalence relations" do
let db =
InMemoryDB.withFactsAndRules
NaiveDatabase.withFactsAndRules
[]
[ "equivalent(Q,Q) :- ."
, "equivalent(R,Q) :- equivalent(Q,R)."
@ -233,8 +233,8 @@ spec = do
`shouldBe` Set.empty
it "can do basic queries" do
let db :: InMemoryDB =
InMemoryDB.withFacts
let db :: NaiveDatabase =
NaiveDatabase.withFacts
[ "parent(\"alice\", \"bob\")."
, "parent(\"bob\", \"carol\")."
]