4

I am working on a haskell program that includes these data type definitions as part of it:

data Term t (deriving Eq) where
Con     ::          a                               -> Term a
And     ::      Term Bool           -> Term Bool    -> Term Bool 
Or      ::      Term Bool           -> Term Bool    -> Term Bool 
Smaller ::      Term Int            -> Term Int     -> Term Bool
Plus    ::          Term Int        -> Term Int     -> Term Int

And data Formula ts where

data Formula ts where
Body   :: Term Bool                     -> Formula ()
Forall :: Show a 
     => [a] -> (Term a -> Formula as) -> Formula (a, as)

and also an eval function, which evaluates each Term t as:

eval :: Term t -> t
eval (Con i) =i
eval (And p q)=eval p && eval q
eval (Or p q)=eval p || eval q
eval(Smaller n m)=eval n < eval m
eval (Plus n m)    = eval n + eval m

And the following function that checks wether a Formula is satisfiable for any possible substitution of values:

satisfiable :: Formula ts -> Bool
satisfiable (Body( sth ))=eval sth
satisfiable (Forall xs f) = any (satisfiable . f . Con) xs

Now, i have been asked to write a solution function that solves a given Formula :

solutions :: Formula ts -> [ts]

Also, i have the following Formulas as testing examples, that expects my solution to behave like this:

ex1 :: Formula ()
ex1 = Body (Con True)

ex2 :: Formula (Int, ())
ex2 = Forall [1..10] $ \n ->
    Body $ n `Smaller` (n `Plus` Con 1)

ex3 :: Formula (Bool, (Int, ()))
ex3 = Forall [False, True] $ \p -> 
  Forall [0..2] $ \n -> 
    Body $ p `Or` (Con 0 `Smaller` n)

the solution function should return:

*Solver>solutions ex1 
[()]

*Solver> solutions ex2
[(1,()),(2,()),(3,()),(4,()),(5,()),(6,()),(7,()),(8,()),(9,()),(10,())]

*Solver> solutions ex3
[(False,(1,())),(False,(2,())),(True,(0,())),(True,(1,())),(True,(2,()))]

My code for this function so far is:

solutions :: Formula ts -> [ts]
solutions(Body(sth))|satisfiable (Body( sth ))=[()]
        |otherwise=[]

solutions(Forall [a] f)|(satisfiable (Forall [a] f))=[(a,(helper $(f.Con) a) )]

|otherwise=[]
solutions(Forall (a:as) f)=solutions(Forall [a] f)++ solutions(Forall as f) 

and the helper function is:

helper :: Formula ts -> ts
helper (Body(sth))|satisfiable (Body( sth ))=()
helper (Forall [a] f)|(satisfiable (Forall [a] f))=(a,((helper.f.Con) a) )

Finally, here is my question: with this solutions function, i can solve formulas which are either like ex1 and ex2 without any problems, but the problem is that i can not solve ex3 .meaning that my function does not work with formulas that include nested "Forall"s . any help with how can i do this, will be appreciated, thanks in advance.

Bahar Bori
  • 41
  • 3

1 Answers1

2

solutions has to be recursive so that it can peel off arbitrary number of Forall layers:

solutions :: Formula ts -> [ts]
solutions (Body term) = [() | eval term]
solutions (Forall xs formula) = [ (x, ys) | x <- xs, ys <- solutions (formula (Con x)) ]

Examples:

λ» solutions ex1
[()]
λ» solutions ex2
[(1,()),(2,()),(3,()),(4,()),(5,()),(6,()),(7,()),(8,()),(9,()),(10,())]
λ» solutions ex3
[(False,(1,())),(False,(2,())),(True,(0,())),(True,(1,())),(True,(2,()))]

(as an aside, I think the Forall name is quite misleading and should be renamed to Exists, since your satisfiable function (and my solutions function, to keep in the spirit) accepts formulae where there's some choice of the variables to evaluate to True)

Cactus
  • 27,075
  • 9
  • 69
  • 149