packages feed

GrammarProducts-0.0.0.2: FormalLanguage/GrammarProduct/Op/Add.hs

{-# LANGUAGE FlexibleInstances #-}

module FormalLanguage.GrammarProduct.Op.Add where

import Control.Lens
import Control.Lens.Fold
import Control.Newtype
import Data.List (genericReplicate)
import Data.Monoid hiding ((<>))
import Data.Semigroup
import qualified Data.Set as S
import Text.Printf

import FormalLanguage.CFG.Grammar



-- | Add two grammars. Implemented as the union of production rules without any
-- renaming.

newtype Add a = Add {runAdd :: a}



-- | Note that the semigroup on Add will create a new rule S_gh -> S_g | S_h in
-- case two start symbols with different rhs exist (If S_g, S_h are the same,
-- there is no problem).

instance Semigroup (Add Grammar) where
  (Add l) <> (Add r)
    | gDim l /= gDim r
    = error $ printf "ERROR: grammars \n%s\n and \n%s\n have different dimensions, cannot unify. (add %d %d)"
                (show l)
                (show r)
                (gDim l)
                (gDim r)
    | otherwise = Add $ Grammar (l^.tsyms <> r^.tsyms)
                                (l^.nsyms <> r^.nsyms) -- TODO add the newly created symbol to the non-terminals (or maybe just run ``fix T+N 's from the rules?'')
                                (l^.epsis <> r^.epsis)
                                (l^.rules <> r^.rules <> t)
                                s
                                (l^.name  <> r^.name)
    where s = case (l^.start,r^.start) of
                (Nothing, Nothing) -> Nothing
                (Nothing, Just k ) -> Just k
                (Just k , Nothing) -> Just k
                (Just k , Just l ) -> if k==l then Just k else error "need to create new symbol, see note on Semigroup (Add Grammar)"
          t = case (l^.start,r^.start) of
                (Just k , Just l ) -> if k==l then S.empty else error "this will create the new rule"
                _                  -> S.empty
                                --(if l^.start == r^.start
                                --  then l^.start
                                --  else error "maybe add another rule and a unique start symbol?")

instance Monoid (Add Grammar) where
  mempty = Add $ Grammar S.empty S.empty S.empty S.empty Nothing ""
  mappend = (<>)

-- idempotency is not made explicit here