module Ideas.Common.Strategy.Derived
(
permute, many, many1, replicate, option, try
, repeat, repeat1, exhaustive
, atomic, (<%>), interleave
, (<@>), (!*>), inits, filterP, hide
) where
import Ideas.Common.Classes
import Ideas.Common.Strategy.Choice
import Ideas.Common.Strategy.Process
import Ideas.Common.Strategy.Sequence
import Ideas.Common.Strategy.Symbol
import Prelude hiding (sequence, replicate, repeat)
import qualified Prelude
split :: (AtomicSymbol a, Choice b)
=> (Process a -> Process a -> b) -> b -> Process a -> b
split op = split2 (op . single) op
split2 :: (AtomicSymbol a, Choice b)
=> (a -> Process a -> b) -> (Process a -> Process a -> b) -> b -> Process a -> b
split2 op1 op2 = withMenu f
where
f a | a == atomicOpen = rec (op2 . (a ~>)) 1
| otherwise = op1 a
rec acc n
| n == 0 = acc done
| otherwise = withMenu g empty
where
g a = rec (acc . (a ~>)) (pm a n)
pm :: AtomicSymbol a => a -> Int -> Int
pm a | a == atomicOpen = succ
| a == atomicClose = pred
| otherwise = id
(!*>) :: AtomicSymbol a => Process a -> Process a -> Process a
a !*> p = atomicOpen ~> a .*. withMenu op (single atomicClose) p
where
op b q
| b == atomicOpen = q
| otherwise = b ~> atomicClose ~> q
filterP :: (a -> Bool) -> Process a -> Process a
filterP cond = fold (\a q -> if cond a then a ~> q else empty) done
hide :: (a -> Bool) -> Process a -> Process a
hide cond = fold (\a q -> if cond a then a ~> q else q) done
atomic :: AtomicSymbol a => Process a -> Process a
atomic p = atomicOpen ~> (p .*. single atomicClose)
interleave :: (AtomicSymbol a, LabelSymbol a) => [Process a] -> Process a
interleave xs = if null xs then done else foldr1 (<%>) xs
(<%>) :: (AtomicSymbol a, LabelSymbol a) => Process a -> Process a -> Process a
p <%> q =
bothAreDone p q .|. ((p %>> q) .|. (q %>> p))
where
bothAreDone = withMenu stop2 . withMenu stop2 done
stop2 _ _ = empty
(%>>) :: (AtomicSymbol a, LabelSymbol a) => Process a -> Process a -> Process a
p %>> q = rec (0 :: Int) p
where
rec n = withMenu op empty
where
op a = a ~> rest
where
next | a == atomicOpen = n+1
| a == atomicClose = n1
| otherwise = n
rest | isEnterSymbol a = rec next
| next > 0 = rec next
| otherwise = (<%> q)
permute :: (Choice a, Sequence a) => [a] -> a
permute as
| null as = done
| otherwise = choice [ s .*. permute ys | (s, ys) <- pickOne as ]
where
pickOne :: [a] -> [(a, [a])]
pickOne [] = []
pickOne (x:xs) = (x, xs) : [ (y, x:ys) | (y, ys) <- pickOne xs ]
(<@>) :: AtomicSymbol a => Process a -> Process a -> Process a
p0 <@> q0 = rec q0 p0
where
rec q = let op b r = b .*. rec r q
in split op (bothOk q)
bothOk = withMenu (\_ _ -> empty) done
inits :: AtomicSymbol a => Process a -> Process a
inits = rec
where
rec p = done .|. split op empty p
op x = (x .*.) . rec
many :: (Sequence a, Fix a, Choice a) => a -> a
many s = fix $ \x -> done .|. (s .*. x)
many1 :: (Sequence a, Fix a, Choice a) => a -> a
many1 s = s .*. many s
replicate :: Sequence a => Int -> a -> a
replicate n = sequence . Prelude.replicate n
option :: (Choice a, Sequence a) => a -> a
option s = s .|. done
try :: (Choice a, Sequence a) => a -> a
try s = s |> done
repeat :: (Sequence a, Fix a, Choice a) => a -> a
repeat s = fix $ \x -> try (s .*. x)
repeat1 :: (Sequence a, Fix a, Choice a) => a -> a
repeat1 s = s .*. repeat s
exhaustive :: (Sequence a, Fix a, Choice a) => [a] -> a
exhaustive = repeat . choice