rest-rewrite-0.1: src/Language/REST/OrderingConstraints.hs
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE FlexibleContexts #-}
module Language.REST.OrderingConstraints
(
OrderingConstraints(..)
, ConstraintGen
, liftC
, cmapConstraints
, numOrderings
, isUnsatisfiable
, intersectAll
, unionAll
, intersectRelation
, runStateConstraints
, singleton
, simplify
) where
import Control.Monad.Identity
import Control.Monad.State.Strict
import qualified Data.List as L
import Data.Hashable
import Debug.Trace
import qualified Data.Set as S
import Prelude hiding (GT, EQ)
import qualified Language.REST.WQO as WQO
import Language.REST.Types
import Language.REST.SMT
type WQO = WQO.WQO
trace' _ x = x
data OrderingConstraints impl m = OC
{ addConstraint :: forall a. (Eq a, Ord a, Hashable a) => WQO a -> impl a -> impl a
, intersect :: forall a. (Show a, Eq a, Ord a, Hashable a) => impl a -> impl a -> impl a
, isSatisfiable :: forall a. (ToSMTVar a Int, Show a, Eq a, Ord a, Hashable a) => impl a -> m Bool
, notStrongerThan :: forall a. (ToSMTVar a Int, Eq a, Ord a, Hashable a) => impl a -> impl a -> m Bool
, noConstraints :: forall a. (Eq a, Ord a, Hashable a) => impl a
, permits :: forall a. (Show a, Eq a, Ord a, Hashable a) => impl a -> WQO a -> Bool
, relevantConstraints :: forall a. (Eq a, Ord a, Hashable a) => impl a -> S.Set a -> S.Set a -> impl a
, union :: forall a. (Eq a, Ord a, Hashable a) => impl a -> impl a -> impl a
, unsatisfiable :: forall a. impl a
, elems :: forall a. (Eq a, Ord a, Hashable a) => impl a -> S.Set a
, getOrdering :: forall a. impl a -> Maybe (WQO a)
, simplify :: forall a. (Eq a, Ord a, Hashable a) => impl a -> impl a
}
numOrderings :: (Show a, Ord a, Eq a, Ord a, Hashable a) => S.Set a -> OrderingConstraints oc m -> oc a -> Int
numOrderings elems impl oc = S.size $ S.filter (permits impl oc) (WQO.orderings elems)
isUnsatisfiable :: (Functor m, ToSMTVar a Int, Show a, Eq a, Ord a, Hashable a) => OrderingConstraints oc m -> oc a -> m Bool
isUnsatisfiable OC{isSatisfiable} c = not <$> isSatisfiable c
singleton :: (Eq a, Ord a, Hashable a) => OrderingConstraints oc m -> WQO a -> oc a
singleton OC{addConstraint, noConstraints} c = addConstraint c noConstraints
intersectAll :: (Eq a, Ord a, Hashable a, Show a, Show (oc a)) => OrderingConstraints oc m -> [oc a] -> oc a
intersectAll OC{noConstraints} [] = noConstraints
intersectAll OC{intersect} (x:xs) = L.foldl' go x xs
where
go t1 t2 = trace' ("Intersect " ++ (show t1)) $ intersect t1 t2
unionAll :: (Eq a, Ord a, Hashable a, Show a, Show (oc a)) => OrderingConstraints oc m -> [oc a] -> oc a
unionAll OC{unsatisfiable} [] = unsatisfiable
unionAll OC{union} (x:xs) = L.foldl' go x xs
where
go t1 t2 = trace' ("Union " ++ (show t1)) $ union t1 t2
intersectRelation ::
(Ord a, Eq a, Ord a, Hashable a, Show a) =>
OrderingConstraints oc m -> oc a -> (a, a, Relation) -> oc a
intersectRelation oc impl (f, g, r) =
case nc r of
Just impl' -> intersect oc impl impl'
Nothing -> unsatisfiable oc
where
nc GT = fmap (singleton oc) (WQO.singleton (f, g, WQO.QGT))
nc EQ = fmap (singleton oc) (WQO.singleton (f, g, WQO.QEQ))
nc GTE = do
wqo1 <- WQO.singleton (f, g, WQO.QGT)
wqo2 <- WQO.singleton (f, g, WQO.QEQ)
return $ union oc (singleton oc wqo1) (singleton oc wqo2)
-- ConstraintGen impl R >= t u returns the constraints on >= that guarantee
-- the resulting relation >=', we have:
-- 1. x >= y implies x >=' y
-- 2. t lift(R(>=')) u
-- Where R generates { == , >=, > } from the underlying ordering
-- R is used to enable optimizations
type ConstraintGen oc base lifted m =
forall m' . (OrderingConstraints oc m' -> Relation -> oc base -> lifted -> lifted -> m (oc base))
cmapConstraints :: (lifted' -> lifted) -> ConstraintGen oc base lifted m -> ConstraintGen oc base lifted' m
cmapConstraints f cgen impl r oc t u = cgen impl r oc (f t) (f u)
liftC :: (m Bool -> m' Bool) -> OrderingConstraints impl m -> OrderingConstraints impl m'
liftC f oc = oc{
isSatisfiable = isSatisfiable'
, notStrongerThan = notStrongerThan'
}
where
isSatisfiable' c1 = f (isSatisfiable oc c1)
notStrongerThan' c1 c2 = f (notStrongerThan oc c1 c2)
runStateConstraints :: ConstraintGen oc base lifted (State a) -> a -> ConstraintGen oc base lifted Identity
runStateConstraints cgen initState impl r oc t u = Identity $ evalState (cgen impl r oc t u) initState