module Ideas.Common.Strategy.Combinators where
import Data.Array
import Data.Graph
import Data.List ((\\))
import Ideas.Common.Id
import Ideas.Common.Rule
import Ideas.Common.Strategy.Abstract
import Ideas.Common.Strategy.Core
import Ideas.Common.Utils (fst3)
import Prelude hiding (not, repeat, fail, sequence)
import qualified Prelude
infixr 2 <%>, <@>
infixr 3 <|>
infixr 4 >|>, |>
infixr 5 <*>
(<*>) :: (IsStrategy f, IsStrategy g) => f a -> g a -> Strategy a
(<*>) = liftCore2 (:*:)
(<|>) :: (IsStrategy f, IsStrategy g) => f a -> g a -> Strategy a
(<|>) = liftCore2 (:|:)
(<%>) :: (IsStrategy f, IsStrategy g) => f a -> g a -> Strategy a
(<%>) = liftCore2 (:%:)
(<@>) :: (IsStrategy f, IsStrategy g) => f a -> g a -> Strategy a
(<@>) = liftCore2 (:@:)
succeed :: Strategy a
succeed = fromCore Succeed
fail :: Strategy a
fail = fromCore Fail
atomic :: IsStrategy f => f a -> Strategy a
atomic = liftCore Atomic
sequence :: IsStrategy f => [f a] -> Strategy a
sequence = foldr ((<*>) . toStrategy) succeed
alternatives :: IsStrategy f => [f a] -> Strategy a
alternatives = foldr ((<|>) . toStrategy) fail
interleave :: IsStrategy f => [f a] -> Strategy a
interleave = foldr ((<%>) . toStrategy) succeed
permute :: IsStrategy f => [f a] -> Strategy a
permute = foldr ((<%>) . atomic) succeed
many :: IsStrategy f => f a -> Strategy a
many a = fix $ \x -> succeed <|> (a <*> x)
many1 :: IsStrategy f => f a -> Strategy a
many1 s = s <*> many s
replicate :: IsStrategy f => Int -> f a -> Strategy a
replicate n = sequence . Prelude.replicate n
option :: IsStrategy f => f a -> Strategy a
option s = s <|> succeed
check :: (a -> Bool) -> Strategy a
check = toStrategy . checkRule "check"
not :: IsStrategy f => f a -> Strategy a
not = liftCore Not
repeat :: IsStrategy f => f a -> Strategy a
repeat a = fix $ \x -> (a <*> x) |> succeed
repeat1 :: IsStrategy f => f a -> Strategy a
repeat1 s = s <*> repeat s
try :: IsStrategy f => f a -> Strategy a
try s = s |> succeed
(>|>) :: (IsStrategy f, IsStrategy g) => f a -> g a -> Strategy a
(>|>) = liftCore2 (:>|>)
(|>) :: (IsStrategy f, IsStrategy g) => f a -> g a -> Strategy a
(|>) = liftCore2 (:|>:)
while :: IsStrategy f => (a -> Bool) -> f a -> Strategy a
while p s = repeat (check p <*> s)
until :: IsStrategy f => (a -> Bool) -> f a -> Strategy a
until p = while (Prelude.not . p)
multi :: (IsId l, IsStrategy f) => l -> f a -> Strategy a
multi l = collapse . label l . repeat1
exhaustive :: IsStrategy f => [f a] -> Strategy a
exhaustive = repeat . alternatives
fix :: (Strategy a -> Strategy a) -> Strategy a
fix f = fromCore (coreFix (toCore . f . fromCore))
remove :: IsStrategy f => f a -> Strategy a
remove = liftCore Remove
collapse :: IsStrategy f => f a -> Strategy a
collapse = liftCore Collapse
hide :: IsStrategy f => f a -> Strategy a
hide = liftCore Hide
type DependencyGraph node key = (Graph, Vertex -> (node, key, [key]), key -> Maybe Vertex)
dependencyGraph:: IsStrategy f => DependencyGraph (f a) key -> Strategy a
dependencyGraph (graph, vertex2data, _) = g2s []
where
g2s seen
| null reachables = succeed
| otherwise = alternatives $ map makePath reachables
where
reachables = filter isReachable $ vertices graph \\ seen
isReachable = null . (\\ seen) . (graph!)
makePath vertex = (fst3 . vertex2data) vertex <*> g2s (vertex:seen)