module Control.Concurrent.CHPSpec.Spec where
import Control.Compose (Flip(..))
import qualified Data.Foldable as F
import Data.List (nub)
data SpecItem' proc comm
= Par [Spec' proc comm]
| Alt [Spec' proc comm]
| Call proc
| Sync comm
| Stop
| Repeat (Spec' proc comm)
deriving (Show)
type Spec' proc comm = [SpecItem' proc comm]
data Dir = DirInput | DirOutput deriving (Eq, Read, Show)
type ProcessId = Integer
type EventId = Integer
type CommId = Either EventId (EventId, Dir, Integer)
type SpecItem = SpecItem' ProcessId CommId
type Spec = Spec' ProcessId CommId
type SpecMod = Spec -> Spec
finalise :: SpecMod -> Spec
finalise f = f []
instance Functor (SpecItem' p) where
fmap _ (Call x) = Call x
fmap f (Sync x) = Sync $ f x
fmap _ Stop = Stop
fmap f (Repeat x) = Repeat $ fmap (fmap f) x
fmap f (Alt x) = Alt $ fmap (fmap (fmap f)) x
fmap f (Par x) = Par $ fmap (fmap (fmap f)) x
instance Functor (Flip SpecItem' c) where
fmap f = Flip . fmap' . unFlip
where
fmap' (Call x) = Call $ f x
fmap' (Sync x) = Sync x
fmap' Stop = Stop
fmap' (Repeat x) = Repeat $ fmap fmap' x
fmap' (Alt x) = Alt $ fmap (fmap fmap') x
fmap' (Par x) = Par $ fmap (fmap fmap') x
instance F.Foldable (SpecItem' p) where
foldr f x (Par xs) = F.foldr (flip $ F.foldr (flip $ F.foldr f)) x xs
foldr f x (Alt xs) = F.foldr (flip $ F.foldr (flip $ F.foldr f)) x xs
foldr _ x (Call _) = x
foldr _ x Stop = x
foldr f x (Sync y) = f y x
foldr f x (Repeat y) = F.foldr (flip $ F.foldr f) x y
instance F.Foldable (Flip SpecItem' c) where
foldr = (\f x -> foldr' f x . unFlip)
where
foldr' f x (Par xs) = F.foldr (flip $ F.foldr (flip $ foldr' f)) x xs
foldr' f x (Alt xs) = F.foldr (flip $ F.foldr (flip $ foldr' f)) x xs
foldr' f x (Call y) = f y x
foldr' _ x (Sync _) = x
foldr' _ x Stop = x
foldr' f x (Repeat y) = F.foldr (flip $ foldr' f) x y
instance (Eq a, Eq b) => Eq (SpecItem' a b) where
(==) (Call x) (Call y) = x == y
(==) (Sync x) (Sync y) = x == y
(==) (Repeat x) (Repeat y) = x == y
(==) (Par x) (Par y) = bagsEqual x y
(==) (Alt x) (Alt y) = x == y
(==) Stop Stop = True
(==) _ _ = False
bagsEqual :: Eq a => [a] -> [a] -> Bool
bagsEqual [] [] = True
bagsEqual _ [] = False
bagsEqual [] _ = False
bagsEqual (x:xs) ys
| 1 + length xs /= length ys = False
| otherwise
= case span (/= x) ys of
(_, []) -> False
(as, _:bs) -> bagsEqual xs (as ++ bs)
checkZipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
checkZipWith f xs ys
| length xs /= length ys = error "checkZipWith, wrong lengths"
| otherwise = zipWith f xs ys
pruneSpec :: (Eq p, Eq c) => Spec' p c -> Spec' p c
pruneSpec = concatMap pruneSpecOne
where
pruneSpecOne :: (Eq p, Eq c) => SpecItem' p c -> Spec' p c
pruneSpecOne (Par [x]) = pruneSpec x
pruneSpecOne (Par xs) = [Par $ map pruneSpec xs]
pruneSpecOne (Alt xs) = [Alt $ nub $ map pruneSpec xs]
pruneSpecOne (Repeat x) = [Repeat $ pruneSpec x]
pruneSpecOne x = [x]
subSpec :: (p -> p') -> (c -> c') -> SpecItem' p c -> SpecItem' p' c'
subSpec fp fc = unFlip . fmap fp . Flip . fmap fc