-- Representation of Prolog Terms, Clauses and Databases
-- Mark P. Jones November 1990, modified for Gofer 20th July 1991,
-- and for Hugs 1.3 June 1996.
--
-- Suitable for use with Hugs 98.
--
module Prolog
( Id, Term(..), Clause(..), Database
, varsIn, renClauses, addClause, emptyDb, termlist, clause
) where
import List
import CombParse
import Char
infix 6 :-
--- Prolog Terms:
type Id = (Int,String)
type Atom = String
data Term = Var Id | Struct Atom [Term]
data Clause = Term :- [Term]
data Database = Db [(Atom,[Clause])]
instance Eq Term where
Var v == Var w = v==w
Struct a ts == Struct b ss = a==b && ts==ss
_ == _ = False
--- Determine the list of variables in a term:
varsIn :: Term -> [Id]
varsIn (Var i) = [i]
varsIn (Struct i ts) = (nub . concat . map varsIn) ts
renameVars :: Int -> Term -> Term
renameVars lev (Var (n,s)) = Var (lev,s)
renameVars lev (Struct s ts) = Struct s (map (renameVars lev) ts)
--- Functions for manipulating databases (as an abstract datatype)
emptyDb :: Database
emptyDb = Db []
renClauses :: Database -> Int -> Term -> [Clause]
renClauses db n (Var _) = []
renClauses db n (Struct a _) = [ r tm:-map r tp | (tm:-tp)<-clausesFor a db ]
where r = renameVars n
clausesFor :: Atom -> Database -> [Clause]
clausesFor a (Db rss) = case dropWhile (\(n,rs) -> n []
((n,rs):_) -> if a==n then rs else []
addClause :: Database -> Clause -> Database
addClause (Db rss) r@(Struct a _ :- _)
= Db (update rss)
where update [] = [(a,[r])]
update (h@(n,rs):rss')
| n==a = (n,rs++[r]) : rss'
| n u . showChar '\n' . v)
[ showWithTerm "\n" rs | (i,rs)<-rss ]
--- Local functions for use in defining instances of Show:
showWithSep :: Show a => String -> [a] -> ShowS
showWithSep s [x] = shows x
showWithSep s (x:xs) = shows x . showString s . showWithSep s xs
showWithTerm :: Show a => String -> [a] -> ShowS
showWithTerm s xs = foldr1 (.) [shows x . showString s | x<-xs]
--- String parsing functions for Terms and Clauses:
--- Local definitions:
letter :: Parser Char
letter = sat (\c->isAlpha c || isDigit c || c `elem` ":;+=-*&%$#@?/.~!")
variable :: Parser Term
variable = sat isUpper `pseq` many letter `pam` makeVar
where makeVar (initial,rest) = Var (0,(initial:rest))
struct :: Parser Term
struct = many letter `pseq` (sptok "(" `pseq` termlist `pseq` sptok ")"
`pam` (\(o,(ts,c))->ts)
`orelse`
okay [])
`pam` (\(name,terms)->Struct name terms)
--- Exports:
term :: Parser Term
term = sp (variable `orelse` struct)
termlist :: Parser [Term]
termlist = listOf term (sptok ",")
clause :: Parser Clause
clause = sp struct `pseq` (sptok ":-" `pseq` listOf term (sptok ",")
`pam` (\(from,body)->body)
`orelse` okay [])
`pseq` sptok "."
`pam` (\(head,(goals,dot))->head:-goals)
--- End of Prolog.hs