2026-01-21 11:24:30 +00:00
|
|
|
{-# HLINT ignore "Redundant flip" #-}
|
2026-01-21 17:11:13 +00:00
|
|
|
{-# LANGUAGE ImportQualifiedPost #-}
|
2026-01-27 16:41:33 +00:00
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
2026-01-23 18:12:47 +00:00
|
|
|
{-# LANGUAGE ScopedTypeVariables #-}
|
2026-01-27 16:41:33 +00:00
|
|
|
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
|
2026-01-29 16:42:53 +00:00
|
|
|
{-# LANGUAGE InstanceSigs #-}
|
2026-01-29 17:27:11 +00:00
|
|
|
{-# LANGUAGE BlockArguments #-}
|
2026-01-27 16:41:33 +00:00
|
|
|
|
2026-01-30 15:39:17 +00:00
|
|
|
module Datalog.InMemoryDB where
|
2026-01-21 11:24:30 +00:00
|
|
|
|
2026-01-27 16:41:33 +00:00
|
|
|
import Control.Exception.Base
|
2026-01-21 11:24:30 +00:00
|
|
|
import Data.Map (Map)
|
2026-01-27 16:41:33 +00:00
|
|
|
import Data.Map qualified as Map
|
2026-01-21 11:24:30 +00:00
|
|
|
import Data.Set (Set)
|
2026-01-21 17:11:13 +00:00
|
|
|
import Data.Set qualified as Set
|
|
|
|
|
import Data.Text (Text)
|
2026-01-30 14:47:29 +00:00
|
|
|
import Datalog.DatalogParser (Literal (..), Statement (..), parseDatalog)
|
2026-01-29 16:30:47 +00:00
|
|
|
import Datalog.Rules
|
2026-01-30 10:27:26 +00:00
|
|
|
import Datalog.DatalogDB
|
2026-01-21 11:24:30 +00:00
|
|
|
|
2026-01-30 15:39:17 +00:00
|
|
|
data InMemoryDB = InMemoryDB
|
2026-01-27 16:41:33 +00:00
|
|
|
{ relations :: Map RelationId Relation
|
|
|
|
|
, constants :: Set Constant
|
2026-01-29 15:07:14 +00:00
|
|
|
} deriving (Show, Eq)
|
2026-01-21 17:11:13 +00:00
|
|
|
|
2026-01-22 10:57:11 +00:00
|
|
|
|
2026-01-30 15:39:17 +00:00
|
|
|
instance DatalogDB InMemoryDB where
|
|
|
|
|
emptyDB :: InMemoryDB
|
|
|
|
|
emptyDB = InMemoryDB
|
2026-01-27 16:41:33 +00:00
|
|
|
{ relations = Map.empty
|
|
|
|
|
, constants = Set.empty -- the Herbrand universe
|
|
|
|
|
}
|
2026-01-21 17:11:13 +00:00
|
|
|
|
2026-01-30 15:39:17 +00:00
|
|
|
lookupRelation :: InMemoryDB -> Text -> Maybe Relation
|
2026-01-29 17:02:27 +00:00
|
|
|
lookupRelation db relationName =
|
|
|
|
|
Map.lookup relationName $ relations db
|
|
|
|
|
|
2026-01-30 15:39:17 +00:00
|
|
|
insertRelation :: InMemoryDB -> Relation -> InMemoryDB
|
2026-01-29 17:27:11 +00:00
|
|
|
insertRelation db relation =
|
|
|
|
|
db {
|
|
|
|
|
relations = Map.insert (_name relation) relation (relations db)
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-30 15:39:17 +00:00
|
|
|
addConstants :: InMemoryDB -> Set Constant -> InMemoryDB
|
2026-01-30 10:55:19 +00:00
|
|
|
addConstants db newConstants =
|
|
|
|
|
db {
|
|
|
|
|
constants = Set.union newConstants (constants db)
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-29 17:27:11 +00:00
|
|
|
lookupRelation00 :: DatalogDB db =>
|
|
|
|
|
Text -> db -> Int -> (Relation -> Relation) -> db
|
|
|
|
|
lookupRelation00 relationName db newArity update =
|
|
|
|
|
insertRelation db (update newRelation)
|
|
|
|
|
where
|
|
|
|
|
newRelation = case lookupRelation db relationName of
|
|
|
|
|
Nothing -> Relation relationName newArity Set.empty []
|
|
|
|
|
Just relation ->
|
|
|
|
|
if _arity relation == newArity then
|
|
|
|
|
relation
|
|
|
|
|
else throw $ BadArityException relationName newArity
|
|
|
|
|
|
2026-01-30 12:53:40 +00:00
|
|
|
lookupRelation000 :: DatalogDB db =>
|
2026-01-29 17:27:11 +00:00
|
|
|
Text -> db -> Int -> Set [Constant] -> (Relation -> Relation) -> db
|
|
|
|
|
lookupRelation000 relationName db newArity tuples update =
|
|
|
|
|
lookupRelation00 relationName db newArity \relation ->
|
|
|
|
|
update relation {
|
|
|
|
|
_tuples = Set.union tuples $ _tuples relation
|
|
|
|
|
}
|
2026-01-28 12:39:32 +00:00
|
|
|
|
2026-01-30 12:53:40 +00:00
|
|
|
withFacts :: DatalogDB db => [Text] -> db
|
2026-01-28 12:39:32 +00:00
|
|
|
withFacts =
|
|
|
|
|
foldr (addFact . extractFact) emptyDB
|
2026-01-27 16:41:33 +00:00
|
|
|
where
|
|
|
|
|
extractFact :: Text -> Literal
|
|
|
|
|
extractFact factText =
|
2026-01-27 17:33:44 +00:00
|
|
|
case parseDatalog factText of
|
2026-01-27 16:41:33 +00:00
|
|
|
Right (Fact fact) -> fact
|
|
|
|
|
Right otherStatement -> throw $ NonFactException factText otherStatement
|
|
|
|
|
Left ex -> throw $ CannotParseStatementException factText ex
|
2026-01-23 18:12:47 +00:00
|
|
|
|
2026-01-30 15:39:17 +00:00
|
|
|
withFactsAndRules :: [Text] -> [Text] -> InMemoryDB
|
2026-01-30 11:00:24 +00:00
|
|
|
withFactsAndRules facts = foldr (addRule . extractRule) (withFacts facts)
|
|
|
|
|
|
2026-01-30 12:53:40 +00:00
|
|
|
query :: forall db . (DatalogDB db) => db -> Text -> Text
|
2026-01-21 17:11:13 +00:00
|
|
|
query db qText =
|
2026-01-27 17:27:18 +00:00
|
|
|
case parseDatalog qText of
|
2026-01-21 17:11:13 +00:00
|
|
|
Right (Query texts literals) -> "#NYI"
|
|
|
|
|
Right otherStatement -> throw $ NonQueryException qText otherStatement
|
|
|
|
|
Left ex -> throw $ CannotParseStatementException qText ex
|