{-# 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 = do c ← liftReader (edgeCardinality inc) require (c ≡ 2) case term of Var v | isLower v → return $ Map.singleton v inc Var v | otherwise → do Variable {name = n} ← nodeAt inc require (n ≡ v) return Map.empty App f x → do 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]