module UniqueLogic.ST.Example.Verify
where
import qualified UniqueLogic.ST.Example.Term as Term
import qualified UniqueLogic.ST.Expression as Expr
import qualified UniqueLogic.ST.System as Sys
import qualified UniqueLogic.ST.Duplicate as Duplicate
import qualified UniqueLogic.ST.MonadTrans as UMT
import UniqueLogic.ST.Expression ((=:=))
import qualified Control.Monad.Exception.Synchronous as ME
import qualified Control.Monad.Trans.Writer as MW
import qualified Control.Monad.Trans.Class as MT
import Control.Monad.Trans.Writer (writer, )
import Control.Monad.Trans.Maybe (MaybeT, mapMaybeT, )
import Control.Monad.ST (ST, runST, )
import Control.Monad (liftM, liftM2, ap, )
import Control.Applicative (Applicative, pure, (<*>), )
import qualified Prelude as P
import Prelude hiding (max, log)
data Assign = Assign Term.Name Term.T
deriving (Show)
type Assigns = [Assign]
data TrackedNumber a = TrackedNumber Term.T a
deriving (Show)
tn1 :: (Term.T -> Term.T) -> (a -> b) -> TrackedNumber a -> TrackedNumber b
tn1 f g (TrackedNumber xt xn) = TrackedNumber (f xt) (g xn)
tn2 :: (Term.T -> Term.T -> Term.T) -> (a -> b -> c) -> TrackedNumber a -> TrackedNumber b -> TrackedNumber c
tn2 f g (TrackedNumber xt xn) (TrackedNumber yt yn) =
TrackedNumber (f xt yt) (g xn yn)
instance Num a => Num (TrackedNumber a) where
fromInteger n = TrackedNumber (fromInteger n) (fromInteger n)
(+) = tn2 (+) (+)
() = tn2 () ()
(*) = tn2 (*) (*)
abs = tn1 abs abs
signum = tn1 signum signum
instance Fractional a => Fractional (TrackedNumber a) where
fromRational n = TrackedNumber (fromRational n) (fromRational n)
(/) = tn2 (/) (/)
instance Eq a => Duplicate.C (TrackedNumber a) where
accept (TrackedNumber _ x) (TrackedNumber _ y) = x==y
instance (Monad m) => Functor (Track m) where
fmap = liftM
instance (Monad m) => Applicative (Track m) where
pure = return
(<*>) = ap
instance (Monad m) => Monad (Track m) where
return = Track . UMT.point
x >>= k = Track $ UMT.bind (runTrack x) (runTrack . k)
instance MT.MonadTrans Track where
lift = Track . MT.lift . MT.lift
instance UMT.C Track where
point = return
bind = (>>=)
instance Sys.C Track where
doUpdate =
Sys.updateAndCheck $ \_ _ ->
UMT.wrap $ Track $ ME.throwT AnonymousException
newtype
Track m a =
Track {runTrack :: ME.ExceptionalT Exception (MW.WriterT Assigns m) a}
data
Exception =
Exception Term.Name (TrackedNumber Rational) (TrackedNumber Rational)
| AnonymousException
deriving (Show)
type Variable s = Sys.Variable Track s (TrackedNumber Rational)
globalVariable :: Term.Name -> ST s (Variable s)
globalVariable name =
Sys.globalVariable
(\al av -> Sys.updateAndCheck (inconsistency name) al av . update name)
inconsistency ::
Monad m =>
Term.Name ->
TrackedNumber Rational ->
TrackedNumber Rational ->
UMT.Wrap Track m ()
inconsistency name old new =
UMT.wrap $ Track $ ME.throwT $ Exception name old new
update ::
Term.Name ->
MaybeT (ST s) (TrackedNumber a) ->
MaybeT (UMT.Wrap Track (ST s)) (TrackedNumber a)
update name act = do
(TrackedNumber t x) <- mapMaybeT UMT.lift act
MT.lift $ UMT.wrap $ Track $ MT.lift $
writer (TrackedNumber (Term.Var name) x, [Assign name t])
example ::
(ME.Exceptional Exception
(Maybe (TrackedNumber Rational),
Maybe (TrackedNumber Rational)),
Assigns)
example =
runST (do
xv <- globalVariable "x"
yv <- globalVariable "y"
MW.runWriterT $ ME.runExceptionalT $ runTrack $ do
Sys.solve $ do
let x = Expr.fromVariable xv
y = Expr.fromVariable yv
x*3 =:= y/2
5 =:= 2+x
MT.lift $ liftM2 (,)
(Sys.query xv)
(Sys.query yv))