module Data.Predicate
(
Predicate
, constant
, failure
, true
, false
, and
, or
, orElse
, (.&.)
, (.|.)
, (|||)
, opt
, def
, mapOkay
, mapFail
, exec
, module Data.Predicate.Result
, module Data.Predicate.Product
) where
import Control.Monad
import Data.Predicate.Product
import Data.Predicate.Result
import Prelude hiding (and, or)
type Predicate a f t = a -> Result f t
constant :: t -> Predicate a f t
constant t _ = return t
true :: Predicate a f ()
true = constant ()
failure :: f -> Predicate a f t
failure f _ = Fail f
false :: Predicate a () t
false = failure ()
infixr 3 .&.
infixr 2 .|.
infixr 2 |||
and :: Predicate a f t -> Predicate a f t' -> Predicate a f (t ::: t')
and f g x = f x `cmp` g x
where
cmp (Okay d y) (Okay w z) = Okay (d + w) (y ::: z)
cmp (Okay _ _) (Fail y) = Fail y
cmp (Fail y) _ = Fail y
or :: Predicate a f t -> Predicate a f t -> Predicate a f t
or f g x = f x `cmp` g x
where
cmp a@(Okay d _) b@(Okay w _) = if w < d then b else a
cmp a@(Okay _ _) (Fail _) = a
cmp (Fail _) b@(Okay _ _) = b
cmp (Fail _) b@(Fail _) = b
orElse :: Predicate a f t -> Predicate a f t' -> Predicate a f (Either t t')
orElse f g x = f x `cmp` g x
where
cmp (Okay d y) (Okay w z) = if w < d then Okay w (Right z) else Okay d (Left y)
cmp (Okay d y) (Fail _) = Okay d (Left y)
cmp (Fail _) (Okay d y) = Okay d (Right y)
cmp (Fail _) (Fail y) = Fail y
(.&.) :: Predicate a f t -> Predicate a f t' -> Predicate a f (t ::: t')
(.&.) = and
(.|.) :: Predicate a f t -> Predicate a f t -> Predicate a f t
(.|.) = or
(|||) :: Predicate a f t -> Predicate a f t' -> Predicate a f (Either t t')
(|||) = orElse
mapOkay :: (t -> Result f t') -> Predicate a f t -> Predicate a f t'
mapOkay f p a =
case p a of
Okay _ x -> f x
Fail x -> Fail x
mapFail :: (f -> Result f' t) -> Predicate a f t -> Predicate a f' t
mapFail f p a =
case p a of
Fail x -> f x
Okay d x -> Okay d x
opt :: Predicate a f t -> Predicate a f (Maybe t)
opt = fmap (result (const $ return Nothing) (\d x -> Okay d (Just x)))
def :: t -> Predicate a f t -> Predicate a f t
def t = fmap (result (const $ return t) Okay)
exec :: Predicate a f t -> a -> (f -> b) -> (t -> b) -> b
exec p a g f = case p a of
Okay _ x -> f x
Fail x -> g x