ideas-0.6: src/Common/Strategy/Prefix.hs
-----------------------------------------------------------------------------
-- Copyright 2010, Open Universiteit Nederland. This file is distributed
-- under the terms of the GNU General Public License. For more information,
-- see the file "LICENSE.txt", which is included in the distribution.
-----------------------------------------------------------------------------
-- |
-- Maintainer : bastiaan.heeren@ou.nl
-- Stability : provisional
-- Portability : portable (depends on ghc)
--
-- A prefix encodes a sequence of steps already performed (a so-called trace),
-- and allows to continue the derivation at that particular point.
--
-----------------------------------------------------------------------------
module Common.Strategy.Prefix
( Prefix, emptyPrefix, makePrefix
, Step(..), prefixToSteps, prefixTree, stepsToRules, lastStepInPrefix
) where
import Common.Apply
import Common.Utils
import Common.Strategy.Abstract
import Common.Strategy.Core
import Common.Transformation
import Common.Derivation
import Common.Strategy.Location
import Common.Strategy.BiasedChoice
import Data.Maybe
-----------------------------------------------------------
--- Prefixes
-- | Abstract data type for a (labeled) strategy with a prefix (a sequence of
-- executed rules). A prefix is still "aware" of the labels that appear in the
-- strategy. A prefix is encoded as a list of integers (and can be reconstructed
-- from such a list: see @makePrefix@). The list is stored in reversed order.
data Prefix a = P [(Int, Bias Step a)] (DerivationTree (Bias Step a) ())
instance Show (Prefix a) where
show (P xs _) = show (reverse (map fst xs))
instance Eq (Prefix a) where
P xs _ == P ys _ = map fst xs == map fst ys
-- | Construct the empty prefix for a labeled strategy
emptyPrefix :: LabeledStrategy a -> Prefix a
emptyPrefix = fromMaybe (error "emptyPrefix") . makePrefix []
-- | Construct a prefix for a given list of integers and a labeled strategy.
makePrefix :: Monad m => [Int] -> LabeledStrategy a -> m (Prefix a)
makePrefix is ls = rec [] is start
where
mkCore = placeBiasLabels . processLabelInfo snd
. addLocation . toCore . toStrategy
start = strategyTree biasT (mkCore ls)
rec acc [] t = return (P acc t)
rec acc (n:ns) t =
case drop n (branches t) of
(step, st):_ -> rec ((n, step):acc) ns st
_ -> fail ("invalid prefix: " ++ show is)
biasT :: Translation (Either (Bias Step a) (StrategyLocation, LabelInfo)) a (Bias Step a)
biasT = (forLabel, Normal . Step)
forLabel (Left bias) = Before bias
forLabel (Right (loc, i)) = Around (Normal (Begin loc i)) (Normal (End loc i))
-- | The @Step@ data type can be used to inspect the structure of the strategy
data Step a = Begin StrategyLocation LabelInfo
| Step (Rule a)
| End StrategyLocation LabelInfo
deriving Show
instance Apply Step where
applyAll (Step r) = applyAll r
applyAll (Begin _ _) = return
applyAll (End _ _) = return
instance Apply Prefix where
applyAll p = results . prefixTree p
-- | Create a derivation tree with a "prefix" as annotation.
prefixTree :: Prefix a -> a -> DerivationTree (Prefix a) a
prefixTree (P xs t) = changeLabel snd . biasTreeG suc . runTree (decorate xs t)
where
suc t = endpoint t || any p (annotations t) || any suc (subtrees t)
p (Step r, _) = isMajorRule r
p _ = False
decorate :: [(Int, Bias Step a)] -> DerivationTree (Bias Step a) () -> DerivationTree (Bias Step a) (Prefix a)
decorate xs t =
let list = zipWith make [0..] (branches t)
make i (s, st) = (s, decorate ((i,s):xs) st)
in addBranches list (singleNode (P xs t) (endpoint t))
-- | Returns the steps that belong to the prefix
prefixToSteps :: Prefix a -> [Step a]
prefixToSteps (P xs _) = [ step | (_, Normal step) <- reverse xs ]
-- | Retrieves the rules from a list of steps
stepsToRules :: [Step a] -> [Rule a]
stepsToRules steps = [ r | Step r <- steps ]
-- | Returns the last rule of a prefix (if such a rule exists)
lastStepInPrefix :: Prefix a -> Maybe (Step a)
lastStepInPrefix (P xs _) = safeHead [ step | (_, Normal step) <- xs ]