term-rewriting-0.1: src/Data/Rewriting/Rules/Rewrite.hs
-- This file is part of the 'term-rewriting' library. It is licensed
-- under an MIT license. See the accompanying 'LICENSE' file for details.
--
-- Authors: Bertram Felgenhauer
{-# LANGUAGE BangPatterns #-}
-- |
-- Simple rewriting.
--
-- Note: The rules are assumed to be non-creating, i.e., variables on the
-- rhs should also occur on the lhs. Rules violating this constraint
-- will have no effect.
module Data.Rewriting.Rules.Rewrite (
Reduct (..),
Strategy,
fullRewrite,
outerRewrite,
innerRewrite,
rootRewrite,
-- * utilities not reexported from "Data.Rewriting.Rules"
nested,
listContexts,
) where
import Data.Rewriting.Substitution
import Data.Rewriting.Pos
import Data.Rewriting.Rule
import Data.Maybe
-- | A reduct. It contains the resulting term, the position that the term
-- was rewritten at, and the applied rule.
data Reduct f v v' = Reduct {
result :: Term f v,
pos :: Pos,
rule :: Rule f v',
subst :: GSubst v' f v
}
-- | A rewrite strategy.
type Strategy f v v' = Term f v -> [Reduct f v v']
-- | Full rewriting: Apply rules anywhere in the term.
--
-- Reducts are returned in pre-order: the first is a leftmost, outermost redex.
fullRewrite :: (Ord v', Eq v, Eq f)
=> [Rule f v'] -> Strategy f v v'
fullRewrite trs t = rootRewrite trs t ++ nested (fullRewrite trs) t
-- | Outer rewriting: Apply rules at outermost redexes.
--
-- Reducts are returned in left to right order.
outerRewrite :: (Ord v', Eq v, Eq f)
=> [Rule f v'] -> Strategy f v v'
outerRewrite trs t = case rootRewrite trs t of
[] -> nested (outerRewrite trs) t
rs -> rs
-- | Inner rewriting: Apply rules at innermost redexes.
--
-- Reducts are returned in left to right order.
innerRewrite :: (Ord v', Eq v, Eq f)
=> [Rule f v'] -> Strategy f v v'
innerRewrite trs t = case nested (innerRewrite trs) t of
[] -> rootRewrite trs t
rs -> rs
-- | Root rewriting: Apply rules only at the root of the term.
--
-- This is mainly useful as a building block for various rewriting strategies.
rootRewrite :: (Ord v', Eq v, Eq f)
=> [Rule f v'] -> Strategy f v v'
rootRewrite trs t = do
r <- trs
s <- maybeToList $ match (lhs r) t
t' <- maybeToList $ gApply s (rhs r)
return Reduct{ result = t', pos = [], rule = r, subst = s }
-- | Nested rewriting: Apply a rewriting strategy to all arguments of a
-- function symbol, left to right. For variables, the result will be empty.
--
-- This is another building block for rewriting strategies.
nested :: Strategy f v v' -> Strategy f v v'
nested _ (Var _) = []
nested s (Fun f ts) = do
(n, cl, t) <- listContexts ts
(\r -> r{ result = Fun f (cl (result r)), pos = n : pos r }) `fmap` s t
-- | Return a list of contexts of a list. Each returned element is an element
-- index (starting from 0), a function that replaces the list element by a
-- new one, and the original element.
listContexts :: [a] -> [(Int, a -> [a], a)]
listContexts = go 0 id where
go !n f [] = []
go !n f (x:xs) = (n, f . (: xs), x) : go (n+1) (f . (x:)) xs