{-# LANGUAGE UnicodeSyntax, MultiParamTypeClasses, FlexibleInstances, FlexibleContexts #-} module TermRewriting (buildRule) where import Prelude.Unicode import GraphRewriting import Data.Char (isLower) import Control.Applicative 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 root ← edge varMap ← buildLHS root lhs buildRHS root varMap rhs buildLHS ∷ (View Vertex n, View [Port] n) ⇒ Edge → Term → Pattern n VarMap buildLHS root term = case term of Var v | isLower v → return $ Map.singleton v root Var v | otherwise → do c ← liftReader (edgeCardinality root) require (c ≡ 2) Variable {name = n} ← nodeWith root require (n ≡ v) return Map.empty App f x → do c ← liftReader (edgeCardinality root) require (c ≡ 2) Applicator {inp = i, out1 = o1, out2 = o2} ← nodeWith root require (i ≡ root) Map.unionWithKey nonLinear <$> buildLHS o1 f <*> buildLHS o2 x where nonLinear v = error $ "Left-hand side is not linear as " ⧺ [v] ⧺ " occurs twice" buildRHS ∷ (View Vertex n, View [Port] n) ⇒ Edge → VarMap → Term → Rule n buildRHS root bindings term = replace $ build term root where build (App f x) inc = do (xEdge,fEdge) ← (,) <$> byEdge <*> byEdge byNode Applicator {inp = inc, out1 = fEdge, out2 = xEdge} build f fEdge >> build x xEdge >> return () build (Var v) inc = if isLower v then maybe freeVar (byWire inc) (Map.lookup v bindings) else byNode Variable {inp = inc, name = v} where freeVar = error $ v : " occurs free on the right-hand side"