module Example.Monad.Quantifiers
  ( run )
  where

import Control.Monad
import Control.Monad.Trans ( liftIO )

import Z3.Monad

run = evalZ3 $ do
  a <- mkFreshIntVar "a"
  b <- mkFreshIntVar "b"
  c <- mkFreshIntVar "c"
  d <- mkFreshIntVar "d"

  a' <- toApp a
  b' <- toApp b
  c' <- toApp c
  d' <- toApp d

  fs <- sequence [ mkEq a =<< mkAdd [ b, c ]
                 , mkExistsConst [] [a'] =<< mkEq a =<< mkAdd [ b, c ]
                 , mkForallConst [] [a', d'] =<< mkExistsConst [] [ b', c' ] =<< join (liftM2 mkEq (mkAdd [ a, b ]) (mkMul [ c, d ]))
                 , mkAdd [ a, b, c, d ] ]

  forM_ fs $ \a -> do
    k <- getAstKind a
    case k of
      Z3_QUANTIFIER_AST -> do
        t  <- isQuantifierForall a
        vs <- getQuantifierBoundVars a
        b  <- getQuantifierBody a
        f  <- substituteVars a vs -- this step only replaces debruijn encoding of the bound variables
        liftIO . putStrLn . ((if t then "universal: " else "existential: ") ++) =<< astToString f
      _ -> liftIO . putStrLn =<< astToString a
