unique-logic-0.3: src/UniqueLogic/ST/Test.hs
module Main where
import qualified UniqueLogic.ST.Expression as Expr
import qualified UniqueLogic.ST.System as Sys
import UniqueLogic.ST.Expression ((=:=))
import qualified Control.Monad.Trans.Class as MT
import qualified Control.Monad.Trans.Writer as MW
import Control.Monad.ST (ST, runST, )
import Control.Monad (join, liftM2, )
import Data.Monoid (Monoid(mempty, mappend))
import Data.List (sortBy, )
import Data.Ord.HT (comparing, )
import qualified Data.NonEmpty as NonEmpty
import qualified Test.QuickCheck as QC
shuffle :: NonEmpty.T [] Int -> [a] -> [a]
shuffle order =
map snd . sortBy (comparing fst) .
zip (NonEmpty.flatten $ NonEmpty.cycle order)
newtype Check s = Check {runCheck :: ST s Bool}
instance Monoid (Check s) where
mempty = Check $ return True
mappend (Check x) (Check y) = Check $ liftM2 (&&) x y
{-
Take a system of six equations and seven variables
where one variable is randomly chosen and initialized with the correct value.
The other six variables must be determined by the solver.
Then we pose the six equations and
finally check whether all variables got the right value.
-}
example :: Int -> NonEmpty.T [] Int -> Bool
example var order =
runST
(join . fmap runCheck . Sys.solve $ MW.execWriterT $ do
let variable ::
(Monoid w) =>
Int -> Rational ->
MW.WriterT (Check s) (Sys.T w s)
(Expr.T Sys.Variable w s Rational)
variable n x = do
v <-
MT.lift $
if mod var 7 == n
then Sys.constant x
else Sys.localVariable
MW.tell $ Check $ fmap (Just x ==) $ Sys.query v
return $ Expr.fromVariable v
c <- variable 0 1
x0 <- variable 1 2
x1 <- variable 2 3
y0 <- variable 3 4
y1 <- variable 4 5
z0 <- variable 5 6
z1 <- variable 6 7
MT.lift $ sequence_ $ shuffle order $
(c+1 =:= x0) :
(x1*2 =:= x0*3) :
(2*c + y0/2 =:= 4) :
(y0 =:= subtract 1 y1) :
(c =:= z0/6) :
(z0*z1 =:= 42) :
[] )
tests :: [(String, IO ())]
tests = [("example", QC.quickCheck example)]
main :: IO ()
main = mapM_ (\(msg, test) -> putStr (msg ++ " ") >> test) tests