module Data.Predicate where
import Prelude hiding (and, or)
import Control.Applicative hiding (Const)
import Control.Monad.State.Strict
import Data.Predicate.Env (Env)
import qualified Data.Predicate.Env as E
type Delta = Double
data Boolean f t
= F f
| T Delta t
deriving (Eq, Show)
class Predicate p a where
type FVal p
type TVal p
apply :: p -> a -> State Env (Boolean (FVal p) (TVal p))
data Const f t where
Const :: t -> Const f t
instance Predicate (Const f t) a where
type FVal (Const f t) = f
type TVal (Const f t) = t
apply (Const a) _ = return (T 0 a)
instance Show t => Show (Const f t) where
show (Const a) = "Const " ++ show a
data Fail f t where
Fail :: f -> Fail f t
instance Predicate (Fail f t) a where
type FVal (Fail f t) = f
type TVal (Fail f t) = t
apply (Fail a) _ = return (F a)
instance Show f => Show (Fail f t) where
show (Fail a) = "Fail " ++ show a
data a :|: b = a :|: b
instance (Predicate a c, Predicate b c, TVal a ~ TVal b, FVal a ~ FVal b) => Predicate (a :|: b) c
where
type FVal (a :|: b) = FVal a
type TVal (a :|: b) = TVal a
apply (a :|: b) r = or <$> apply a r <*> apply b r
where
or x@(T d0 _) y@(T d1 _) = if d1 < d0 then y else x
or x@(T _ _) (F _) = x
or (F _) x@(T _ _) = x
or (F _) x@(F _) = x
instance (Show a, Show b) => Show (a :|: b) where
show (a :|: b) = "(" ++ show a ++ " | " ++ show b ++ ")"
type a :+: b = Either a b
data a :||: b = a :||: b
instance (Predicate a c, Predicate b c, FVal a ~ FVal b) => Predicate (a :||: b) c
where
type FVal (a :||: b) = FVal a
type TVal (a :||: b) = TVal a :+: TVal b
apply (a :||: b) r = or <$> apply a r <*> apply b r
where
or (T d0 t0) (T d1 t1) = if d1 < d0 then T d1 (Right t1) else T d0 (Left t0)
or (T d t) (F _) = T d (Left t)
or (F _) (T d t) = T d (Right t)
or (F _) (F f) = F f
instance (Show a, Show b) => Show (a :||: b) where
show (a :||: b) = "(" ++ show a ++ " || " ++ show b ++ ")"
data a :*: b = a :*: b deriving (Eq, Show)
data a :&: b = a :&: b
instance (Predicate a c, Predicate b c, FVal a ~ FVal b) => Predicate (a :&: b) c
where
type FVal (a :&: b) = FVal a
type TVal (a :&: b) = TVal a :*: TVal b
apply (a :&: b) r = and <$> apply a r <*> apply b r
where
and (T d x) (T w y) = T (d + w) (x :*: y)
and (T _ _) (F f) = F f
and (F f) _ = F f
instance (Show a, Show b) => Show (a :&: b) where
show (a :&: b) = "(" ++ show a ++ " & " ++ show b ++ ")"
eval :: Predicate p a => p -> a -> Boolean (FVal p) (TVal p)
eval p a = evalState (apply p a) E.empty
with :: (Monad m, Predicate p a) => p -> a -> (TVal p -> m ()) -> m ()
with p a f =
case eval p a of
T _ x -> f x
_ -> return ()