ideas-0.6: src/Common/Strategy/Abstract.hs
{-# OPTIONS -XFlexibleInstances #-}
-----------------------------------------------------------------------------
-- 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)
--
-----------------------------------------------------------------------------
module Common.Strategy.Abstract
( Strategy, IsStrategy(..)
, LabeledStrategy, label, unlabel
, fullDerivationTree, derivationTree, rulesInStrategy
, mapRules, mapRulesS, cleanUpStrategy
-- Accessors to the underlying representation
, toCore, fromCore, liftCore, liftCore2, fixCore, makeLabeledStrategy
, toLabeledStrategy
, LabelInfo, strategyName, processLabelInfo, changeInfo, makeInfo
, removed, collapsed, hidden, labelName, IsLabeled(..)
) where
import Common.Utils (commaList)
import Common.Strategy.Core
import Common.Strategy.BiasedChoice
import Common.Apply
import Common.Rewriting (RewriteRule(..))
import Common.Transformation
import Common.Derivation
import Common.Uniplate
-----------------------------------------------------------
--- Strategy data-type
-- | Abstract data type for strategies
newtype Strategy a = S { toCore :: Core LabelInfo a }
instance Show (Strategy a) where
show = show . toCore
instance Apply Strategy where
applyAll s = results . fullDerivationTree s
-----------------------------------------------------------
--- The information used as label in a strategy
data LabelInfo = Info
{ labelName :: String
, removed :: Bool
, collapsed :: Bool
, hidden :: Bool
}
instance Show LabelInfo where
show info =
let ps = ["removed" | removed info] ++
["collapsed" | collapsed info] ++
["hidden" | hidden info]
extra = " (" ++ commaList ps ++ ")"
in show (labelName info) ++ if null ps then "" else extra
makeInfo :: String -> LabelInfo
makeInfo s = Info s False False False
-----------------------------------------------------------
--- Type class
-- | Type class to turn values into strategies
class Apply f => IsStrategy f where
toStrategy :: f a -> Strategy a
instance IsStrategy (Core LabelInfo) where
toStrategy = S
instance IsStrategy Strategy where
toStrategy = id
instance IsStrategy (LabeledStrategy) where
toStrategy (LS info (S core)) =
case core of
Rule Nothing r | name r == labelName info ->
S (Rule (Just info) r)
_ -> S (Label info core)
instance IsStrategy Rule where -- Major rules receive a label
toStrategy r
| isMajorRule r = toStrategy (toLabeled r)
| otherwise = S (Rule Nothing r)
instance IsStrategy RewriteRule where
toStrategy r =
toStrategy (makeRule (ruleName r) (RewriteRule r))
-----------------------------------------------------------
--- Labeled Strategy data-type
-- | A strategy which is labeled with a string
data LabeledStrategy a = LS
{ labelInfo :: LabelInfo -- ^ Returns information associated with this label
, unlabel :: Strategy a -- ^ Removes the label from a strategy
}
makeLabeledStrategy :: IsStrategy f => LabelInfo -> f a -> LabeledStrategy a
makeLabeledStrategy info = LS info . toStrategy
toLabeledStrategy :: Monad m => Strategy a -> m (LabeledStrategy a)
toLabeledStrategy s =
case toCore s of
Label l c -> return (makeLabeledStrategy l (fromCore c))
_ -> fail "Strategy without label"
strategyName :: LabeledStrategy a -> String
strategyName = getLabel
instance Show (LabeledStrategy a) where
show s = show (labelInfo s) ++ ": " ++ show (unlabel s)
instance Apply LabeledStrategy where
applyAll = applyAll . toStrategy
class IsLabeled f where
toLabeled :: f a -> LabeledStrategy a
instance IsLabeled LabeledStrategy where
toLabeled = id
instance IsLabeled Rule where
toLabeled r = LS (makeInfo (name r)) (S (Rule Nothing r))
instance IsLabeled RewriteRule where
toLabeled r = toLabeled (makeRule (ruleName r) (RewriteRule r))
-- | Labels a strategy with a string
label :: IsStrategy f => String -> f a -> LabeledStrategy a
label l = LS (makeInfo l) . toStrategy
getLabel :: IsLabeled f => f a -> String
getLabel = labelName . labelInfo . toLabeled
changeInfo :: IsLabeled f => (LabelInfo -> LabelInfo) -> f a -> LabeledStrategy a
changeInfo f a = LS (f info) s
where LS info s = toLabeled a
-----------------------------------------------------------
--- Process Label Information
processLabelInfo :: (l -> LabelInfo) -> Core l a -> Core l a
processLabelInfo getInfo = mapCore forLabel forRule
where
forLabel l c
| removed info = Fail
| collapsed info = Rule (Just l) asRule
| otherwise = new
where
new | hidden info = mapRule minorRule (Label l c)
| otherwise = Label l c
info = getInfo l
asRule = makeSimpleRuleList (labelName info ++ " (collapsed)") (applyAll new)
forRule (Just l) r
| removed info = Fail
| hidden info = Rule (Just l) (minorRule r)
| otherwise = Rule (Just l) r
where
info = getInfo l
forRule _ r = Rule Nothing r
-----------------------------------------------------------
--- Remaining functions
-- | Returns the derivation tree for a strategy and a term, including all
-- minor rules
fullDerivationTree :: IsStrategy f => f a -> a -> DerivationTree (Rule a) a
fullDerivationTree = makeBiasedTree p . processLabelInfo id . toCore . toStrategy
where
p t = endpoint t || any isMajorRule (annotations t) || any p (subtrees t)
-- | Returns the derivation tree for a strategy and a term with only major rules
derivationTree :: IsStrategy f => f a -> a -> DerivationTree (Rule a) a
derivationTree s = mergeSteps isMajorRule . fullDerivationTree s
-- | Returns a list of all major rules that are part of a labeled strategy
rulesInStrategy :: IsStrategy f => f a -> [Rule a]
rulesInStrategy f = [ r | Rule _ r <- universe (toCore (toStrategy f)), isMajorRule r ]
-- | Apply a function to all the rules that make up a labeled strategy
mapRules :: (Rule a -> Rule b) -> LabeledStrategy a -> LabeledStrategy b
mapRules f (LS n s) = LS n (mapRulesS f s)
mapRulesS :: (Rule a -> Rule b) -> Strategy a -> Strategy b
mapRulesS f = S . mapRule f . toCore
-- | Use a function as do-after hook for all rules in a labeled strategy
cleanUpStrategy :: (a -> a) -> LabeledStrategy a -> LabeledStrategy a
cleanUpStrategy f (LS n s) = mapRules g (LS n (S core))
where
core = Rule Nothing (doAfter f idRule) :*: toCore s
g r | isMajorRule r = doAfter f r
| otherwise = r
-----------------------------------------------------------
--- Functions to lift the core combinators
fromCore :: Core LabelInfo a -> Strategy a
fromCore = toStrategy
liftCore :: IsStrategy f => (Core LabelInfo a -> Core LabelInfo a) -> f a -> Strategy a
liftCore f = fromCore . f . toCore . toStrategy
liftCore2 :: (IsStrategy f, IsStrategy g) => (Core LabelInfo a -> Core LabelInfo a -> Core LabelInfo a) -> f a -> g a -> Strategy a
liftCore2 f = liftCore . f . toCore . toStrategy
fixCore :: (Core l a -> Core l a) -> Core l a
fixCore f = Rec i (f (Var i)) -- disadvantage: function f is applied twice
where
s = coreVars (f (Rule Nothing idRule))
i = if null s then 0 else maximum s + 1