{-# LANGUAGE UnicodeSyntax, MultiParamTypeClasses, FlexibleInstances, FlexibleContexts #-} module TermRewriting (buildRule) where import Prelude.Unicode import GraphRewriting import GraphRewriting.Pattern import GraphRewriting.Graph.Read import GraphRewriting.Graph.Write import Data.Char (isLower) import Control.Monad import Data.Map (Map) import qualified Data.Map as Map import Term import Graph type VarMap = Map Char Edge buildRule ∷ (View Vertex n, View [Port] n) ⇒ Term → Term → Rule n buildRule lhs rhs = do (inc, varMap) ← buildLHS lhs buildRHS varMap rhs inc buildLHS ∷ (View Vertex n, View [Port] n) ⇒ Term → Pattern n (Edge, VarMap) buildLHS term = do e ← edge varMap ← build term e return (e, varMap) where build term inc = case term of Var v | isLower v → return $ Map.singleton v inc Var v | otherwise → do c ← liftReader (edgeCardinality inc) require (c ≡ 2) Variable {name = n} ← nodeAt inc require (n ≡ v) return Map.empty App f x → do c ← liftReader (edgeCardinality inc) require (c ≡ 2) Applicator {inp = i, out1 = o1, out2 = o2} ← nodeAt inc require (i ≡ inc) liftM2 (Map.unionWithKey nonLinear) (build f o1) (build x o2) where nonLinear v = error $ "Left-hand side is not linear as " ⧺ [v] ⧺ " occurs twice" buildRHS ∷ (View Vertex n, View [Port] n) ⇒ VarMap → Term → Edge → Rule n buildRHS bindings term inc = replace (reqEdges term) (build term inc) where reqEdges (App f x) = 2 + reqEdges f + reqEdges x reqEdges (Var v) = 0 build (App f x) inc (fEdge:xEdge:edges) = let (fEdges,xEdges) = splitAt (reqEdges f) edges in Node Applicator {inp = inc, out1 = fEdge, out2 = xEdge} : build f fEdge fEdges ⧺ build x xEdge xEdges build (Var v) inc [] = singleton $ if isLower v then maybe freeVar (Wire inc) (Map.lookup v bindings) else Node Variable {inp = inc, name = v} where freeVar = error $ [v] ⧺ " occurs free on the right-hand side" singleton x = [x]