hat-2.7.0.1: examples/Clausify.hs
-- Reducing propositions to clausal form.
-- Colin Runciman, University of York.
-- Original version, 18/10/90.
-- This is Version 5 (see JFP Heap Profiling paper) translated for nhc.
module Main(main) where
main :: IO ()
main = do
inp <- getContents
putStr (concatMap clauses (lines inp))
data StackFrame = Ast Formula | Lex Char
type Stack = [StackFrame]
data Formula =
Tru |
Sym Char |
Not Formula |
Dis Formula Formula |
Con Formula Formula |
Imp Formula Formula |
Eqv Formula Formula
type Clause = (String,String)
-- separate positive and negative literals, eliminating duplicates
clause :: Formula -> Clause
clause p = clause' p ([] , [])
clause' :: Formula -> Clause -> Clause
clause' (Dis p q) x = clause' p (clause' q x)
clause' (Sym s) (c,a) = (insert s c , a)
clause' (Not (Sym s)) (c,a) = (c , insert s a)
-- the main pipeline from propositional formulae to printed clauses
clauses :: String -> String
clauses s = concat (map disp ( unicl ( split ( disin ( negin ( elim ( parse
s )))))))
-- push disjunctions beneath conjunctions
disin :: Formula -> Formula
disin (Con p q) = Con (disin p) (disin q)
disin (Dis p q) = disin' (disin p) (disin q)
disin p = p
disin' :: Formula -> Formula -> Formula
disin' (Con p q) r = Con (disin' p r) (disin' q r)
disin' p (Con q r) = Con (disin' p q) (disin' p r)
disin' p q = Dis p q
-- format pair of lists of propositional symbols as clausal axiom
disp :: Clause -> String
disp (l,r) = interleave l spaces ++ "<=" ++ interleave spaces r ++ "\n"
-- eliminate connectives other than not, disjunction and conjunction
elim :: Formula -> Formula
elim (Not p) = Not (elim p)
elim (Dis p q) = Dis (elim p) (elim q)
elim (Con p q) = Con (elim p) (elim q)
elim (Imp p q) = Dis (Not (elim p)) (elim q)
elim (Eqv f f') = Con (elim (Imp f f')) (elim (Imp f' f))
elim p = p
-- insertion of an item (here a prop symbol) into an ordered list
insert :: Char -> String -> String
insert x [] = [x]
insert x yys@(y:ys) = if x < y then x:yys
else if x > y then y:insert x ys
else yys
interleave :: [a] -> [a] -> [a]
interleave (x:xs) ys = x : interleave ys xs
interleave [] _ = []
-- shift negation to innermost positions
negin :: Formula -> Formula
negin (Not (Not p)) = negin p
negin (Not (Con p q)) = Dis (negin (Not p)) (negin (Not q))
negin (Not (Dis p q)) = Con (negin (Not p)) (negin (Not q))
negin (Dis p q) = Dis (negin p) (negin q)
negin (Con p q) = Con (negin p) (negin q)
negin p = p
-- the priorities of symbols during parsing
opri :: Char -> Int
opri '(' = 0
opri '=' = 1
opri '>' = 2
opri '|' = 3
opri '&' = 4
opri '~' = 5
-- parsing a propositional formula
parse :: String -> Formula
-- parse t = f where [Ast f] = parse' t []
parse t = case parse' t [] of
Ast f : [] -> f
parse' :: String -> Stack -> Stack
parse' [] s = redstar s
parse' (' ':t) s = parse' t s
parse' ('(':t) s = parse' t (Lex '(' : s)
parse' (')':t) s = parse' t (x:s')
where
(x : Lex '(' : s') = redstar s
parse' (c:t) s = if 'a'<= c && c <= 'z' then parse' t (Ast (Sym c) : s)
else if spri s > opri c then parse' (c:t) (red s)
else parse' t (Lex c : s)
-- reduction of the parse stack
red :: Stack -> Stack
red (Ast p : Lex '=' : Ast q : s) = Ast (Eqv q p) : s
red (Ast p : Lex '>' : Ast q : s) = Ast (Imp q p) : s
red (Ast p : Lex '|' : Ast q : s) = Ast (Dis q p) : s
red (Ast p : Lex '&' : Ast q : s) = Ast (Con q p) : s
red (Ast p : Lex '~' : s) = Ast (Not p) : s
-- iterative reduction of the parse stack
redstar :: Stack -> Stack
redstar = while ((/=) 0 . spri) red
spaces :: String
spaces = repeat ' '
-- split CNF formula into a list of conjuncts
split :: Formula -> [Formula]
split (Con p q) = split p ++ split q
split Tru = []
split p = [p]
-- priority of the parse stack
spri :: Stack -> Int
spri (Ast x : Lex c : s) = opri c
spri s = 0
-- does any symbol appear in both consequent and antecedant of clause
tautclause :: Clause -> Bool
tautclause (c,a) = intersect c a /= []
intersect :: Eq a => [a] -> [a] -> [a]
intersect = filter . (flip elem)
-- form unique clausal axioms excluding tautologies
unicl :: [Formula] -> [Clause]
unicl = filterset (not . tautclause) . map clause
filterset :: Eq a => (a->Bool) -> [a] -> [a]
filterset = filterset' []
filterset' s p [] = []
filterset' s p (x:xs) = if not (x `elem` s) && p x then x:filterset' (x:s) p xs
else filterset' s p xs
while :: (a->Bool) -> (a->a) -> a -> a
while p f x = if p x then while p f (f x) else x