content: module Database
     ( createDB
     , hasPredicate
     , getClauses
     , asserta
     , assertz
     , abolish
     , Signature(), signature
     )
  where
  
  import Data.Map (Map)
  import qualified Data.Map as Map
  
  import Syntax
  
  
  data Signature = Signature Atom Int deriving (Ord, Eq)
  instance Show Signature where
     show (Signature name arity) = name ++ "/" ++ show arity
  
  signature :: Term -> Signature
  signature (Struct name ts) = Signature name (length ts)
  
  
  newtype Database = DB (Map Signature [Clause])
  
  hasPredicate sig (DB index) = Map.member sig index
  
  createDB clauses emptyPredicates = DB $
     foldr (\clause -> Map.insertWith' (++) (signature (lhs clause)) [clause])
           (Map.fromList [ (signature (Struct name []), []) | name <- emptyPredicates ])
           clauses
  
  getClauses term (DB index) = maybe [] id $ Map.lookup (signature term) index
  
  
  asserta fact (DB index) = DB $ Map.insertWith (++)        (signature fact) [Clause fact []] index
  assertz fact (DB index) = DB $ Map.insertWith (flip (++)) (signature fact) [Clause fact []] index
  abolish fact (DB index) = DB $ Map.adjust deleteFact (signature fact) index
     where deleteFact (Clause t []:cs) | t == fact = cs
           deleteFact (_          :cs)             = cs
           deleteFact []                           = []
  