transformations-0.1.0.0: Generics/MultiRec/Transformations/RewriteRules.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE GADTs #-}
module Generics.MultiRec.Transformations.RewriteRules (
Transformation, Transform, apply, insert, AnyInsert (..)
) where
import Generics.MultiRec hiding ( foldM )
import Generics.MultiRec.Rewriting
import Generics.MultiRec.Zipper (Zipper, Loc, leave, enter, update)
import Data.Maybe ( fromJust )
import Control.Monad ( (>=>), foldM )
--------------------------------------------------------------------------------
-- Patch
--------------------------------------------------------------------------------
-- Basically, a class synonym
class (Zipper phi (PF phi), Rewrite phi) => Transform phi
instance Transform phi => Rewrite phi
-- An edit is a list of:
type Transformation phi a = [ AnyInsert phi a ]
-- Existential for insertion
data AnyInsert phi a where
AnyInsert ::
-- Proof
phi ix
-- A path to the location to edit
-> (Loc phi I0 a -> Maybe (Loc phi I0 a))
-- The rewrite rule to apply there
-> Rule phi ix
-> AnyInsert phi a
insert :: El phi ix => (Loc phi I0 a -> Maybe (Loc phi I0 a)) -> Rule phi ix
-> AnyInsert phi a
insert = AnyInsert proof
-- Patching is terribly simple: at the given locations, apply all the rules,
-- then exit the zipper.
apply :: Transform phi => Transformation phi a -> phi a -> a -> Maybe a
apply rs p x = fmap leave $ foldM appRule (enter p x) rs
where appRule a (AnyInsert p' l r) = l a >>=
updateM (\p'' -> case eqS p' p'' of
Nothing -> const Nothing
Just Refl -> rewriteM r)
updateM :: (forall xi. phi xi -> xi -> Maybe xi)
-> Loc phi I0 ix -> Maybe (Loc phi I0 ix)
-- updateM f (Loc p (I0 x) s) = f p x >>= \y -> Loc p (I0 y) s
updateM f = Just . update (\p -> maybe (error "updateM") id . f p)