packages feed

GenI 0.20.2 → 0.22

raw patch · 86 files changed

+10501/−13047 lines, 86 filesdep +GenIdep +MaybeTdep +bytestringdep −paralleldep −test-framework-quickcheckdep −uniplatedep ~QuickCheckdep ~basedep ~binarysetup-changedPVP ok

version bump matches the API change (PVP)

Dependencies added: GenI, MaybeT, bytestring, cabal-macosx, deepseq, hslogger, old-locale, ordered, smallcheck, syb, test-framework-quickcheck2, test-framework-smallcheck, text, time, yaml-light

Dependencies removed: parallel, test-framework-quickcheck, uniplate, wx

Dependency ranges changed: QuickCheck, base, binary, filepath, json, mtl, parsec, split, test-framework, utf8-string

API changes (from Hackage documentation)

- NLP.GenI.Btypes: Auxiliar :: Ptype
- NLP.GenI.Btypes: AvPair :: String -> GeniVal -> AvPair
- NLP.GenI.Btypes: Foot :: GType
- NLP.GenI.Btypes: GAnon :: GeniVal
- NLP.GenI.Btypes: GConst :: [String] -> GeniVal
- NLP.GenI.Btypes: GN :: NodeName -> Flist -> Flist -> Bool -> [String] -> GType -> Bool -> String -> GNode
- NLP.GenI.Btypes: GVar :: String -> GeniVal
- NLP.GenI.Btypes: ILE :: [String] -> String -> [GeniVal] -> Flist -> Flist -> Flist -> Ptype -> Sem -> [SemPols] -> ILexEntry
- NLP.GenI.Btypes: Initial :: Ptype
- NLP.GenI.Btypes: Lex :: GType
- NLP.GenI.Btypes: Other :: GType
- NLP.GenI.Btypes: Subs :: GType
- NLP.GenI.Btypes: TT :: [GeniVal] -> String -> String -> Flist -> Ptype -> Maybe Sem -> [String] -> Tree a -> Ttree a
- NLP.GenI.Btypes: TestCase :: String -> String -> SemInput -> [String] -> [(String, Map (String, String) [String])] -> TestCase
- NLP.GenI.Btypes: Unspecified :: Ptype
- NLP.GenI.Btypes: alphaConvert :: (Collectable a, DescendGeniVal a) => String -> a -> a
- NLP.GenI.Btypes: alphaConvertById :: (Collectable a, DescendGeniVal a, Idable a) => a -> a
- NLP.GenI.Btypes: avAtt :: AvPair -> String
- NLP.GenI.Btypes: avVal :: AvPair -> GeniVal
- NLP.GenI.Btypes: class Collectable a
- NLP.GenI.Btypes: class DescendGeniVal a
- NLP.GenI.Btypes: class Idable a
- NLP.GenI.Btypes: collect :: (Collectable a) => a -> Set String -> Set String
- NLP.GenI.Btypes: data AvPair
- NLP.GenI.Btypes: data GNode
- NLP.GenI.Btypes: data GType
- NLP.GenI.Btypes: data GeniVal
- NLP.GenI.Btypes: data ILexEntry
- NLP.GenI.Btypes: data Ptype
- NLP.GenI.Btypes: data TestCase
- NLP.GenI.Btypes: data Ttree a
- NLP.GenI.Btypes: descendGeniVal :: (DescendGeniVal a) => (GeniVal -> GeniVal) -> a -> a
- NLP.GenI.Btypes: emptyGNode :: GNode
- NLP.GenI.Btypes: emptyLE :: ILexEntry
- NLP.GenI.Btypes: emptyMacro :: MTtree
- NLP.GenI.Btypes: emptyPred :: Pred
- NLP.GenI.Btypes: foot :: Tree GNode -> GNode
- NLP.GenI.Btypes: fromGConst :: GeniVal -> [String]
- NLP.GenI.Btypes: fromGVar :: GeniVal -> String
- NLP.GenI.Btypes: gCategory :: Flist -> Maybe GeniVal
- NLP.GenI.Btypes: gaconstr :: GNode -> Bool
- NLP.GenI.Btypes: ganchor :: GNode -> Bool
- NLP.GenI.Btypes: gdown :: GNode -> Flist
- NLP.GenI.Btypes: glexeme :: GNode -> [String]
- NLP.GenI.Btypes: gnname :: GNode -> NodeName
- NLP.GenI.Btypes: gnnameIs :: NodeName -> GNode -> Bool
- NLP.GenI.Btypes: gorigin :: GNode -> String
- NLP.GenI.Btypes: gtype :: GNode -> GType
- NLP.GenI.Btypes: gup :: GNode -> Flist
- NLP.GenI.Btypes: idOf :: (Idable a) => a -> Integer
- NLP.GenI.Btypes: iequations :: ILexEntry -> Flist
- NLP.GenI.Btypes: ifamname :: ILexEntry -> String
- NLP.GenI.Btypes: ifilters :: ILexEntry -> Flist
- NLP.GenI.Btypes: iinterface :: ILexEntry -> Flist
- NLP.GenI.Btypes: instance [overlap ok] (Collectable a) => Collectable (Maybe a)
- NLP.GenI.Btypes: instance [overlap ok] (Collectable a) => Collectable (Tree a)
- NLP.GenI.Btypes: instance [overlap ok] (Collectable a) => Collectable (Ttree a)
- NLP.GenI.Btypes: instance [overlap ok] (Collectable a) => Collectable [a]
- NLP.GenI.Btypes: instance [overlap ok] (Collectable a, Collectable b, Collectable c) => Collectable (a, b, c)
- NLP.GenI.Btypes: instance [overlap ok] (Data a) => Data (Ttree a)
- NLP.GenI.Btypes: instance [overlap ok] (DescendGeniVal a) => DescendGeniVal (Map k a)
- NLP.GenI.Btypes: instance [overlap ok] (DescendGeniVal a) => DescendGeniVal (String, a)
- NLP.GenI.Btypes: instance [overlap ok] (Show a) => Show (Ttree a)
- NLP.GenI.Btypes: instance [overlap ok] Biplate (Maybe Sem) GeniVal
- NLP.GenI.Btypes: instance [overlap ok] Biplate (Tree GNode) GeniVal
- NLP.GenI.Btypes: instance [overlap ok] Biplate (Ttree GNode) GeniVal
- NLP.GenI.Btypes: instance [overlap ok] Biplate (Ttree String) GeniVal
- NLP.GenI.Btypes: instance [overlap ok] Biplate AvPair GeniVal
- NLP.GenI.Btypes: instance [overlap ok] Biplate GNode GeniVal
- NLP.GenI.Btypes: instance [overlap ok] Biplate ILexEntry GeniVal
- NLP.GenI.Btypes: instance [overlap ok] Biplate Pred GeniVal
- NLP.GenI.Btypes: instance [overlap ok] Collectable AvPair
- NLP.GenI.Btypes: instance [overlap ok] Collectable GNode
- NLP.GenI.Btypes: instance [overlap ok] Collectable GeniVal
- NLP.GenI.Btypes: instance [overlap ok] Collectable ILexEntry
- NLP.GenI.Btypes: instance [overlap ok] Data AvPair
- NLP.GenI.Btypes: instance [overlap ok] Data GNode
- NLP.GenI.Btypes: instance [overlap ok] Data GType
- NLP.GenI.Btypes: instance [overlap ok] Data ILexEntry
- NLP.GenI.Btypes: instance [overlap ok] Data Ptype
- NLP.GenI.Btypes: instance [overlap ok] DescendGeniVal (Ttree GNode)
- NLP.GenI.Btypes: instance [overlap ok] DescendGeniVal ([String], Flist)
- NLP.GenI.Btypes: instance [overlap ok] DescendGeniVal AvPair
- NLP.GenI.Btypes: instance [overlap ok] DescendGeniVal GNode
- NLP.GenI.Btypes: instance [overlap ok] DescendGeniVal ILexEntry
- NLP.GenI.Btypes: instance [overlap ok] DescendGeniVal Pred
- NLP.GenI.Btypes: instance [overlap ok] Eq AvPair
- NLP.GenI.Btypes: instance [overlap ok] Eq GNode
- NLP.GenI.Btypes: instance [overlap ok] Eq GType
- NLP.GenI.Btypes: instance [overlap ok] Eq ILexEntry
- NLP.GenI.Btypes: instance [overlap ok] Eq Ptype
- NLP.GenI.Btypes: instance [overlap ok] Ord AvPair
- NLP.GenI.Btypes: instance [overlap ok] Show AvPair
- NLP.GenI.Btypes: instance [overlap ok] Show GNode
- NLP.GenI.Btypes: instance [overlap ok] Show GType
- NLP.GenI.Btypes: instance [overlap ok] Show ILexEntry
- NLP.GenI.Btypes: instance [overlap ok] Show Ptype
- NLP.GenI.Btypes: instance [overlap ok] Show TestCase
- NLP.GenI.Btypes: instance [overlap ok] Typeable AvPair
- NLP.GenI.Btypes: instance [overlap ok] Typeable GNode
- NLP.GenI.Btypes: instance [overlap ok] Typeable GType
- NLP.GenI.Btypes: instance [overlap ok] Typeable ILexEntry
- NLP.GenI.Btypes: instance [overlap ok] Typeable Ptype
- NLP.GenI.Btypes: instance [overlap ok] Typeable1 Ttree
- NLP.GenI.Btypes: iparams :: ILexEntry -> [GeniVal]
- NLP.GenI.Btypes: iptype :: ILexEntry -> Ptype
- NLP.GenI.Btypes: isAnon :: GeniVal -> Bool
- NLP.GenI.Btypes: isConst :: GeniVal -> Bool
- NLP.GenI.Btypes: isVar :: GeniVal -> Bool
- NLP.GenI.Btypes: isemantics :: ILexEntry -> Sem
- NLP.GenI.Btypes: isempols :: ILexEntry -> [SemPols]
- NLP.GenI.Btypes: iword :: ILexEntry -> [String]
- NLP.GenI.Btypes: lexemeAttributes :: [String]
- NLP.GenI.Btypes: mergeSubst :: Subst -> Subst -> Subst
- NLP.GenI.Btypes: params :: Ttree a -> [GeniVal]
- NLP.GenI.Btypes: pfamily :: Ttree a -> String
- NLP.GenI.Btypes: pidname :: Ttree a -> String
- NLP.GenI.Btypes: pinterface :: Ttree a -> Flist
- NLP.GenI.Btypes: plugTree :: Tree NodeName -> NodeName -> Tree NodeName -> Tree NodeName
- NLP.GenI.Btypes: psemantics :: Ttree a -> Maybe Sem
- NLP.GenI.Btypes: ptrace :: Ttree a -> [String]
- NLP.GenI.Btypes: ptype :: Ttree a -> Ptype
- NLP.GenI.Btypes: replace :: (DescendGeniVal a) => Subst -> a -> a
- NLP.GenI.Btypes: replaceList :: (DescendGeniVal a) => [(String, GeniVal)] -> a -> a
- NLP.GenI.Btypes: root :: Tree a -> a
- NLP.GenI.Btypes: rootUpd :: Tree a -> a -> Tree a
- NLP.GenI.Btypes: setAnchor :: [String] -> Tree GNode -> Tree GNode
- NLP.GenI.Btypes: setLexeme :: [String] -> Tree GNode -> Tree GNode
- NLP.GenI.Btypes: showAv :: AvPair -> String
- NLP.GenI.Btypes: showFlist :: Flist -> String
- NLP.GenI.Btypes: showLexeme :: [String] -> String
- NLP.GenI.Btypes: showPairs :: Flist -> String
- NLP.GenI.Btypes: showPred :: Pred -> String
- NLP.GenI.Btypes: showSem :: Sem -> String
- NLP.GenI.Btypes: sortFlist :: Flist -> Flist
- NLP.GenI.Btypes: sortSem :: Sem -> Sem
- NLP.GenI.Btypes: spliceTree :: NodeName -> Tree NodeName -> NodeName -> Tree NodeName -> Tree NodeName
- NLP.GenI.Btypes: subsumeSem :: Sem -> Sem -> [(Sem, Subst)]
- NLP.GenI.Btypes: tcExpected :: TestCase -> [String]
- NLP.GenI.Btypes: tcName :: TestCase -> String
- NLP.GenI.Btypes: tcOutputs :: TestCase -> [(String, Map (String, String) [String])]
- NLP.GenI.Btypes: tcSem :: TestCase -> SemInput
- NLP.GenI.Btypes: tcSemString :: TestCase -> String
- NLP.GenI.Btypes: toKeys :: Sem -> [String]
- NLP.GenI.Btypes: tree :: Ttree a -> Tree a
- NLP.GenI.Btypes: type Flist = [AvPair]
- NLP.GenI.Btypes: type Lexicon = Map String [ILexEntry]
- NLP.GenI.Btypes: type LitConstr = (Pred, [String])
- NLP.GenI.Btypes: type MTtree = Ttree GNode
- NLP.GenI.Btypes: type Macros = [MTtree]
- NLP.GenI.Btypes: type MorphLexEntry = (String, String, Flist)
- NLP.GenI.Btypes: type NodeName = String
- NLP.GenI.Btypes: type Pred = (GeniVal, GeniVal, [GeniVal])
- NLP.GenI.Btypes: type Sem = [Pred]
- NLP.GenI.Btypes: type SemInput = (Sem, Flist, [LitConstr])
- NLP.GenI.Btypes: type SemPols = [Int]
- NLP.GenI.Btypes: type Subst = Map String GeniVal
- NLP.GenI.Btypes: unify :: (Monad m) => [GeniVal] -> [GeniVal] -> m ([GeniVal], Subst)
- NLP.GenI.Btypes: unifyFeat :: (Monad m) => Flist -> Flist -> m (Flist, Subst)
- NLP.GenI.BtypesBinary: instance [overlap ok] (Binary a) => Binary (Ttree a)
- NLP.GenI.BtypesBinary: instance [overlap ok] Binary AvPair
- NLP.GenI.BtypesBinary: instance [overlap ok] Binary GNode
- NLP.GenI.BtypesBinary: instance [overlap ok] Binary GType
- NLP.GenI.BtypesBinary: instance [overlap ok] Binary GeniVal
- NLP.GenI.BtypesBinary: instance [overlap ok] Binary ILexEntry
- NLP.GenI.BtypesBinary: instance [overlap ok] Binary Ptype
- NLP.GenI.Builder: LemmaPlus :: String -> Flist -> LemmaPlus
- NLP.GenI.Builder: chart_size :: String
- NLP.GenI.Builder: class IafAble a
- NLP.GenI.Builder: data LemmaPlus
- NLP.GenI.Builder: dependentSem :: IafMap -> String -> Sem
- NLP.GenI.Builder: fromUniConst :: (Monad m) => GeniVal -> m String
- NLP.GenI.Builder: getIdx :: Flist -> [GeniVal]
- NLP.GenI.Builder: iafAcc :: (IafAble a) => a -> [String]
- NLP.GenI.Builder: iafBadSem :: (IafAble a) => IafMap -> SemBitMap -> BitVector -> (a -> BitVector) -> a -> BitVector
- NLP.GenI.Builder: iafInacc :: (IafAble a) => a -> [String]
- NLP.GenI.Builder: iafNewAcc :: (IafAble a) => a -> [String]
- NLP.GenI.Builder: iafSetAcc :: (IafAble a) => [String] -> a -> a
- NLP.GenI.Builder: iafSetInacc :: (IafAble a) => [String] -> a -> a
- NLP.GenI.Builder: initNullBuilder :: Input -> Params -> ((), Statistics)
- NLP.GenI.Builder: instance [overlap ok] Biplate UninflectedDisjunction GeniVal
- NLP.GenI.Builder: instance [overlap ok] Collectable UninflectedDisjunction
- NLP.GenI.Builder: instance [overlap ok] Data UninflectedDisjunction
- NLP.GenI.Builder: instance [overlap ok] DescendGeniVal UninflectedDisjunction
- NLP.GenI.Builder: instance [overlap ok] Eq LemmaPlus
- NLP.GenI.Builder: instance [overlap ok] JSON LemmaPlus
- NLP.GenI.Builder: instance [overlap ok] Ord LemmaPlus
- NLP.GenI.Builder: instance [overlap ok] Show LemmaPlus
- NLP.GenI.Builder: instance [overlap ok] Show UninflectedDisjunction
- NLP.GenI.Builder: instance [overlap ok] Typeable UninflectedDisjunction
- NLP.GenI.Builder: literalArgs :: Pred -> [GeniVal]
- NLP.GenI.Builder: lpFeats :: LemmaPlus -> Flist
- NLP.GenI.Builder: lpLemma :: LemmaPlus -> String
- NLP.GenI.Builder: modifyStats :: (Metric -> Metric) -> BuilderState st ()
- NLP.GenI.Builder: namedMetric :: String -> Metric
- NLP.GenI.Builder: nullBuilder :: Builder () (NullState ()) Params
- NLP.GenI.Builder: nullFilter :: (Monad s) => DispatchFilter s a
- NLP.GenI.Builder: num_comparisons :: String
- NLP.GenI.Builder: num_iterations :: String
- NLP.GenI.Builder: parsecToJSON :: (Monad m) => String -> CharParser () b -> String -> m b
- NLP.GenI.Builder: recalculateAccesibility :: (IafAble a) => a -> a
- NLP.GenI.Builder: semToIafMap :: Sem -> IafMap
- NLP.GenI.Builder: ts_iafFailure :: [String] -> [Pred] -> String
- NLP.GenI.Builder: type Derivation = TagDerivation
- NLP.GenI.Builder: type IafMap = Map String Sem
- NLP.GenI.Builder: type LemmaPlusSentence = [LemmaPlus]
- NLP.GenI.Builder: type NullState a = BuilderState () a
- NLP.GenI.Configuration: AdjOpts :: Optimisation
- NLP.GenI.Configuration: BatchDirFlg :: FilePath -> BatchDirFlg
- NLP.GenI.Configuration: DetectPolaritiesFlg :: (Set PolarityAttr) -> DetectPolaritiesFlg
- NLP.GenI.Configuration: DisableGuiFlg :: () -> DisableGuiFlg
- NLP.GenI.Configuration: DumpDerivationFlg :: () -> DumpDerivationFlg
- NLP.GenI.Configuration: EarlyDeathFlg :: () -> EarlyDeathFlg
- NLP.GenI.Configuration: EarlyNa :: Optimisation
- NLP.GenI.Configuration: ExtraPolaritiesFlg :: (Map PolarityKey Interval) -> ExtraPolaritiesFlg
- NLP.GenI.Configuration: FromStdinFlg :: () -> FromStdinFlg
- NLP.GenI.Configuration: GeniHand :: GrammarType
- NLP.GenI.Configuration: HelpFlg :: () -> HelpFlg
- NLP.GenI.Configuration: Iaf :: Optimisation
- NLP.GenI.Configuration: InstructionsFileFlg :: FilePath -> InstructionsFileFlg
- NLP.GenI.Configuration: LexiconFlg :: FilePath -> LexiconFlg
- NLP.GenI.Configuration: MacrosFlg :: FilePath -> MacrosFlg
- NLP.GenI.Configuration: MetricsFlg :: [String] -> MetricsFlg
- NLP.GenI.Configuration: MorphCmdFlg :: String -> MorphCmdFlg
- NLP.GenI.Configuration: MorphInfoFlg :: FilePath -> MorphInfoFlg
- NLP.GenI.Configuration: NoConstraints :: Optimisation
- NLP.GenI.Configuration: NoLoadTestSuiteFlg :: () -> NoLoadTestSuiteFlg
- NLP.GenI.Configuration: NullBuilder :: BuilderType
- NLP.GenI.Configuration: OptimisationsFlg :: [Optimisation] -> OptimisationsFlg
- NLP.GenI.Configuration: OutputFileFlg :: String -> OutputFileFlg
- NLP.GenI.Configuration: PartialFlg :: () -> PartialFlg
- NLP.GenI.Configuration: PolOpts :: Optimisation
- NLP.GenI.Configuration: Polarised :: Optimisation
- NLP.GenI.Configuration: PreAnchored :: GrammarType
- NLP.GenI.Configuration: PreCompiled :: GrammarType
- NLP.GenI.Configuration: Prms :: GrammarType -> BuilderType -> [Flag] -> Params
- NLP.GenI.Configuration: RankingConstraintsFlg :: FilePath -> RankingConstraintsFlg
- NLP.GenI.Configuration: RegressionTestModeFlg :: () -> RegressionTestModeFlg
- NLP.GenI.Configuration: RootFeatureFlg :: Flist -> RootFeatureFlg
- NLP.GenI.Configuration: RunUnitTestFlg :: () -> RunUnitTestFlg
- NLP.GenI.Configuration: SemFiltered :: Optimisation
- NLP.GenI.Configuration: SimpleBuilder :: BuilderType
- NLP.GenI.Configuration: SimpleOnePhaseBuilder :: BuilderType
- NLP.GenI.Configuration: StatsFileFlg :: FilePath -> StatsFileFlg
- NLP.GenI.Configuration: TestCaseFlg :: String -> TestCaseFlg
- NLP.GenI.Configuration: TestInstructionsFlg :: [Instruction] -> TestInstructionsFlg
- NLP.GenI.Configuration: TestSuiteFlg :: FilePath -> TestSuiteFlg
- NLP.GenI.Configuration: TimeoutFlg :: Integer -> TimeoutFlg
- NLP.GenI.Configuration: TracesFlg :: FilePath -> TracesFlg
- NLP.GenI.Configuration: VerboseModeFlg :: () -> VerboseModeFlg
- NLP.GenI.Configuration: VersionFlg :: () -> VersionFlg
- NLP.GenI.Configuration: ViewCmdFlg :: String -> ViewCmdFlg
- NLP.GenI.Configuration: data BatchDirFlg
- NLP.GenI.Configuration: data BuilderType
- NLP.GenI.Configuration: data DetectPolaritiesFlg
- NLP.GenI.Configuration: data DisableGuiFlg
- NLP.GenI.Configuration: data DumpDerivationFlg
- NLP.GenI.Configuration: data EarlyDeathFlg
- NLP.GenI.Configuration: data ExtraPolaritiesFlg
- NLP.GenI.Configuration: data Flag
- NLP.GenI.Configuration: data FromStdinFlg
- NLP.GenI.Configuration: data GrammarType
- NLP.GenI.Configuration: data HelpFlg
- NLP.GenI.Configuration: data InstructionsFileFlg
- NLP.GenI.Configuration: data LexiconFlg
- NLP.GenI.Configuration: data MacrosFlg
- NLP.GenI.Configuration: data MetricsFlg
- NLP.GenI.Configuration: data MorphCmdFlg
- NLP.GenI.Configuration: data MorphInfoFlg
- NLP.GenI.Configuration: data NoLoadTestSuiteFlg
- NLP.GenI.Configuration: data Optimisation
- NLP.GenI.Configuration: data OptimisationsFlg
- NLP.GenI.Configuration: data OutputFileFlg
- NLP.GenI.Configuration: data PartialFlg
- NLP.GenI.Configuration: data RankingConstraintsFlg
- NLP.GenI.Configuration: data RegressionTestModeFlg
- NLP.GenI.Configuration: data RootFeatureFlg
- NLP.GenI.Configuration: data RunUnitTestFlg
- NLP.GenI.Configuration: data StatsFileFlg
- NLP.GenI.Configuration: data TestCaseFlg
- NLP.GenI.Configuration: data TestInstructionsFlg
- NLP.GenI.Configuration: data TestSuiteFlg
- NLP.GenI.Configuration: data TimeoutFlg
- NLP.GenI.Configuration: data TracesFlg
- NLP.GenI.Configuration: data VerboseModeFlg
- NLP.GenI.Configuration: data VersionFlg
- NLP.GenI.Configuration: data ViewCmdFlg
- NLP.GenI.Configuration: getFlag :: (Show f, Show x, Typeable f, Typeable x) => (x -> f) -> [Flag] -> Maybe x
- NLP.GenI.Configuration: hasFlag :: (Typeable f, Typeable x) => (x -> f) -> [Flag] -> Bool
- NLP.GenI.Configuration: instance [overlap ok] Eq BatchDirFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq BuilderFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq BuilderType
- NLP.GenI.Configuration: instance [overlap ok] Eq DetectPolaritiesFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq DisableGuiFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq DumpDerivationFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq EarlyDeathFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq ExtraPolaritiesFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq Flag
- NLP.GenI.Configuration: instance [overlap ok] Eq FromStdinFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq GrammarType
- NLP.GenI.Configuration: instance [overlap ok] Eq GrammarTypeFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq HelpFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq InstructionsFileFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq LexiconFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq MacrosFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq MetricsFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq MorphCmdFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq MorphInfoFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq NoLoadTestSuiteFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq Optimisation
- NLP.GenI.Configuration: instance [overlap ok] Eq OptimisationsFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq OutputFileFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq PartialFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq RankingConstraintsFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq RegressionTestModeFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq RootFeatureFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq RunUnitTestFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq StatsFileFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq TestCaseFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq TestInstructionsFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq TestSuiteFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq TimeoutFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq TracesFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq VerboseModeFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq VersionFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq ViewCmdFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq WeirdFlg
- NLP.GenI.Configuration: instance [overlap ok] Show BatchDirFlg
- NLP.GenI.Configuration: instance [overlap ok] Show BuilderFlg
- NLP.GenI.Configuration: instance [overlap ok] Show BuilderType
- NLP.GenI.Configuration: instance [overlap ok] Show DetectPolaritiesFlg
- NLP.GenI.Configuration: instance [overlap ok] Show DisableGuiFlg
- NLP.GenI.Configuration: instance [overlap ok] Show DumpDerivationFlg
- NLP.GenI.Configuration: instance [overlap ok] Show EarlyDeathFlg
- NLP.GenI.Configuration: instance [overlap ok] Show ExtraPolaritiesFlg
- NLP.GenI.Configuration: instance [overlap ok] Show Flag
- NLP.GenI.Configuration: instance [overlap ok] Show FromStdinFlg
- NLP.GenI.Configuration: instance [overlap ok] Show GrammarType
- NLP.GenI.Configuration: instance [overlap ok] Show GrammarTypeFlg
- NLP.GenI.Configuration: instance [overlap ok] Show HelpFlg
- NLP.GenI.Configuration: instance [overlap ok] Show InstructionsFileFlg
- NLP.GenI.Configuration: instance [overlap ok] Show LexiconFlg
- NLP.GenI.Configuration: instance [overlap ok] Show MacrosFlg
- NLP.GenI.Configuration: instance [overlap ok] Show MetricsFlg
- NLP.GenI.Configuration: instance [overlap ok] Show MorphCmdFlg
- NLP.GenI.Configuration: instance [overlap ok] Show MorphInfoFlg
- NLP.GenI.Configuration: instance [overlap ok] Show NoLoadTestSuiteFlg
- NLP.GenI.Configuration: instance [overlap ok] Show Optimisation
- NLP.GenI.Configuration: instance [overlap ok] Show OptimisationsFlg
- NLP.GenI.Configuration: instance [overlap ok] Show OutputFileFlg
- NLP.GenI.Configuration: instance [overlap ok] Show Params
- NLP.GenI.Configuration: instance [overlap ok] Show PartialFlg
- NLP.GenI.Configuration: instance [overlap ok] Show RankingConstraintsFlg
- NLP.GenI.Configuration: instance [overlap ok] Show RegressionTestModeFlg
- NLP.GenI.Configuration: instance [overlap ok] Show RootFeatureFlg
- NLP.GenI.Configuration: instance [overlap ok] Show RunUnitTestFlg
- NLP.GenI.Configuration: instance [overlap ok] Show StatsFileFlg
- NLP.GenI.Configuration: instance [overlap ok] Show TestCaseFlg
- NLP.GenI.Configuration: instance [overlap ok] Show TestInstructionsFlg
- NLP.GenI.Configuration: instance [overlap ok] Show TestSuiteFlg
- NLP.GenI.Configuration: instance [overlap ok] Show TimeoutFlg
- NLP.GenI.Configuration: instance [overlap ok] Show TracesFlg
- NLP.GenI.Configuration: instance [overlap ok] Show VerboseModeFlg
- NLP.GenI.Configuration: instance [overlap ok] Show VersionFlg
- NLP.GenI.Configuration: instance [overlap ok] Show ViewCmdFlg
- NLP.GenI.Configuration: instance [overlap ok] Show WeirdFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable BatchDirFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable BuilderFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable BuilderType
- NLP.GenI.Configuration: instance [overlap ok] Typeable DetectPolaritiesFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable DisableGuiFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable DumpDerivationFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable EarlyDeathFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable ExtraPolaritiesFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable Flag
- NLP.GenI.Configuration: instance [overlap ok] Typeable FromStdinFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable GrammarType
- NLP.GenI.Configuration: instance [overlap ok] Typeable GrammarTypeFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable HelpFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable InstructionsFileFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable LexiconFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable MacrosFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable MetricsFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable MorphCmdFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable MorphInfoFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable NoLoadTestSuiteFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable Optimisation
- NLP.GenI.Configuration: instance [overlap ok] Typeable OptimisationsFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable OutputFileFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable PartialFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable RankingConstraintsFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable RegressionTestModeFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable RootFeatureFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable RunUnitTestFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable StatsFileFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable TestCaseFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable TestInstructionsFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable TestSuiteFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable TimeoutFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable TracesFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable VerboseModeFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable VersionFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable ViewCmdFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable WeirdFlg
- NLP.GenI.Configuration: setFlag :: (Eq f, Show f, Show x, Typeable f, Typeable x) => (x -> f) -> x -> [Flag] -> [Flag]
- NLP.GenI.Configuration: type Instruction = (FilePath, Maybe [String])
- NLP.GenI.General: boundsCheck :: Int -> [a] -> Bool
- NLP.GenI.General: exitTimeout :: IO ()
- NLP.GenI.General: groupAndCount :: (Eq a, Ord a) => [a] -> [(a, Int)]
- NLP.GenI.General: instance [overlap ok] Eq AlphaNum
- NLP.GenI.General: instance [overlap ok] Ord AlphaNum
- NLP.GenI.General: instance [overlap ok] Typeable TimeOut
- NLP.GenI.General: lazySlurp :: ForeignPtr Word8 -> Int -> Int -> IO String
- NLP.GenI.General: multiGroupByFM :: (Ord b) => (a -> [b]) -> [a] -> (Map b [a])
- NLP.GenI.General: readFile' :: FilePath -> IO String
- NLP.GenI.General: withTimeout :: Integer -> IO a -> IO a -> IO a
- NLP.GenI.Geni: CompleteResult :: ResultType
- NLP.GenI.Geni: GeniResult :: LemmaPlusSentence -> [String] -> Derivation -> [GeniLexSel] -> Int -> [OtViolation] -> ResultType -> GeniResult
- NLP.GenI.Geni: PartialResult :: ResultType
- NLP.GenI.Geni: ST :: Params -> Macros -> Lexicon -> MorphFn -> SemInput -> String -> [TestCase] -> OtRanking -> [String] -> [String] -> ProgState
- NLP.GenI.Geni: chooseLexCand :: Lexicon -> Sem -> [ILexEntry]
- NLP.GenI.Geni: combine :: Macros -> Lexicon -> Tags
- NLP.GenI.Geni: data GeniResult
- NLP.GenI.Geni: data ProgState
- NLP.GenI.Geni: data ResultType
- NLP.GenI.Geni: emptyProgState :: Params -> ProgState
- NLP.GenI.Geni: getTraces :: ProgState -> String -> [String]
- NLP.GenI.Geni: gr :: ProgState -> Macros
- NLP.GenI.Geni: grDerivation :: GeniResult -> Derivation
- NLP.GenI.Geni: grLemmaSentence :: GeniResult -> LemmaPlusSentence
- NLP.GenI.Geni: grLexSelection :: GeniResult -> [GeniLexSel]
- NLP.GenI.Geni: grRanking :: GeniResult -> Int
- NLP.GenI.Geni: grRealisations :: GeniResult -> [String]
- NLP.GenI.Geni: grResultType :: GeniResult -> ResultType
- NLP.GenI.Geni: grViolations :: GeniResult -> [OtViolation]
- NLP.GenI.Geni: groupAndCount :: (Eq a, Ord a) => [a] -> [(a, Int)]
- NLP.GenI.Geni: initGeni :: ProgStateRef -> IO (Input)
- NLP.GenI.Geni: instance [overlap ok] Eq GeniLexSel
- NLP.GenI.Geni: instance [overlap ok] Eq GeniResult
- NLP.GenI.Geni: instance [overlap ok] Eq ResultType
- NLP.GenI.Geni: instance [overlap ok] Error LexCombineError
- NLP.GenI.Geni: instance [overlap ok] JSON GeniLexSel
- NLP.GenI.Geni: instance [overlap ok] JSON GeniResult
- NLP.GenI.Geni: instance [overlap ok] JSON ResultType
- NLP.GenI.Geni: instance [overlap ok] Ord GeniLexSel
- NLP.GenI.Geni: instance [overlap ok] Ord GeniResult
- NLP.GenI.Geni: instance [overlap ok] Ord ResultType
- NLP.GenI.Geni: instance [overlap ok] Show LexCombineError
- NLP.GenI.Geni: le :: ProgState -> Lexicon
- NLP.GenI.Geni: lemmaSentenceString :: GeniResult -> String
- NLP.GenI.Geni: loadEverything :: ProgStateRef -> IO ()
- NLP.GenI.Geni: loadGeniMacros :: ProgStateRef -> IO ()
- NLP.GenI.Geni: loadLexicon :: ProgStateRef -> IO ()
- NLP.GenI.Geni: loadRanking :: ProgStateRef -> IO ()
- NLP.GenI.Geni: loadTargetSemStr :: ProgStateRef -> String -> IO ()
- NLP.GenI.Geni: loadTestSuite :: ProgStateRef -> IO [TestCase]
- NLP.GenI.Geni: morphinf :: ProgState -> MorphFn
- NLP.GenI.Geni: pa :: ProgState -> Params
- NLP.GenI.Geni: prettyResult :: ProgState -> GeniResult -> String
- NLP.GenI.Geni: ranking :: ProgState -> OtRanking
- NLP.GenI.Geni: readRanking :: Bool -> FilePath -> IO OtRanking
- NLP.GenI.Geni: runGeni :: ProgStateRef -> Builder st it Params -> IO ([GeniResult], Statistics, st)
- NLP.GenI.Geni: runGeniWithSelector :: ProgStateRef -> Selector -> Builder st it Params -> IO ([GeniResult], Statistics, st)
- NLP.GenI.Geni: showRealisations :: [String] -> String
- NLP.GenI.Geni: tcase :: ProgState -> String
- NLP.GenI.Geni: traces :: ProgState -> [String]
- NLP.GenI.Geni: ts :: ProgState -> SemInput
- NLP.GenI.Geni: tsuite :: ProgState -> [TestCase]
- NLP.GenI.Geni: type ProgStateRef = IORef ProgState
- NLP.GenI.Geni: type Selector = ProgStateRef -> IO ([TagElem], [ILexEntry])
- NLP.GenI.Geni: warnings :: ProgState -> [String]
- NLP.GenI.GeniParsers: geniDerivations :: Parser [TestCaseOutput]
- NLP.GenI.GeniParsers: geniFeats :: Parser Flist
- NLP.GenI.GeniParsers: geniLanguageDef :: LanguageDef ()
- NLP.GenI.GeniParsers: geniLexicon :: Parser [ILexEntry]
- NLP.GenI.GeniParsers: geniMacros :: Parser [MTtree]
- NLP.GenI.GeniParsers: geniMorphInfo :: Parser [(String, Flist)]
- NLP.GenI.GeniParsers: geniPolarities :: Parser (Map PolarityKey Interval)
- NLP.GenI.GeniParsers: geniSemanticInput :: Parser (Sem, Flist, [LitConstr])
- NLP.GenI.GeniParsers: geniSemantics :: Parser Sem
- NLP.GenI.GeniParsers: geniTagElems :: Parser [TagElem]
- NLP.GenI.GeniParsers: geniTestSuite :: Parser [TestCase]
- NLP.GenI.GeniParsers: geniTestSuiteString :: Parser [String]
- NLP.GenI.GeniParsers: geniValue :: Parser GeniVal
- NLP.GenI.GeniParsers: geniWord :: Parser String
- NLP.GenI.GeniParsers: geniWords :: Parser String
- NLP.GenI.GeniParsers: instance [overlap ok] GeniShow SemInputString
- NLP.GenI.GeniParsers: parseFromFile :: Parser a -> SourceName -> IO (Either ParseError a)
- NLP.GenI.GeniParsers: tillEof :: Parser a -> Parser a
- NLP.GenI.GeniParsers: toSemInputString :: SemInput -> String -> SemInputString
- NLP.GenI.GeniShow: geniShowKeyword :: String -> ShowS
- NLP.GenI.GeniShow: geniShowSemInput :: SemInput -> ShowS
- NLP.GenI.GeniShow: instance [overlap ok] (GeniShow a) => GeniShow (Tree a)
- NLP.GenI.GeniShow: instance [overlap ok] (GeniShow a) => GeniShow (Ttree a)
- NLP.GenI.GeniShow: instance [overlap ok] (GeniShow a) => GeniShow [a]
- NLP.GenI.GeniShow: instance [overlap ok] GeniShow AvPair
- NLP.GenI.GeniShow: instance [overlap ok] GeniShow GNode
- NLP.GenI.GeniShow: instance [overlap ok] GeniShow GeniVal
- NLP.GenI.GeniShow: instance [overlap ok] GeniShow Pred
- NLP.GenI.GeniShow: instance [overlap ok] GeniShow Ptype
- NLP.GenI.GeniShow: instance [overlap ok] GeniShow TagElem
- NLP.GenI.GeniShow: instance [overlap ok] GeniShow TestCase
- NLP.GenI.GeniShow: parens :: String -> String
- NLP.GenI.GeniShow: squares :: String -> String
- NLP.GenI.GeniVal: GAnon :: GeniVal
- NLP.GenI.GeniVal: GConst :: [String] -> GeniVal
- NLP.GenI.GeniVal: GTestString :: String -> GTestString
- NLP.GenI.GeniVal: GTestString2 :: String -> GTestString2
- NLP.GenI.GeniVal: GVar :: String -> GeniVal
- NLP.GenI.GeniVal: fromGConst :: GeniVal -> [String]
- NLP.GenI.GeniVal: fromGTestString :: GTestString -> String
- NLP.GenI.GeniVal: fromGTestString2 :: GTestString2 -> String
- NLP.GenI.GeniVal: fromGVar :: GeniVal -> String
- NLP.GenI.GeniVal: instance [overlap ok] (Functor f, DescendGeniVal a) => DescendGeniVal (f a)
- NLP.GenI.GeniVal: instance [overlap ok] Arbitrary GTestString
- NLP.GenI.GeniVal: instance [overlap ok] Arbitrary GTestString2
- NLP.GenI.GeniVal: instance [overlap ok] Arbitrary GeniVal
- NLP.GenI.GeniVal: instance [overlap ok] Data GeniVal
- NLP.GenI.GeniVal: instance [overlap ok] DescendGeniVal GeniVal
- NLP.GenI.GeniVal: instance [overlap ok] Eq GeniVal
- NLP.GenI.GeniVal: instance [overlap ok] NFData GeniVal
- NLP.GenI.GeniVal: instance [overlap ok] Ord GeniVal
- NLP.GenI.GeniVal: instance [overlap ok] Show GeniVal
- NLP.GenI.GeniVal: instance [overlap ok] Typeable GeniVal
- NLP.GenI.GeniVal: instance [overlap ok] Uniplate GeniVal
- NLP.GenI.GeniVal: mergeSubst :: Subst -> Subst -> Subst
- NLP.GenI.GeniVal: newtype GTestString
- NLP.GenI.GeniVal: newtype GTestString2
- NLP.GenI.GeniVal: prependToSubst :: (String, GeniVal) -> Subst -> Subst
- NLP.GenI.GeniVal: prop_unify_anon :: [GeniVal] -> Bool
- NLP.GenI.GeniVal: prop_unify_self :: [GeniVal] -> Property
- NLP.GenI.GeniVal: prop_unify_sym :: [GeniVal] -> [GeniVal] -> Property
- NLP.GenI.GeniVal: qc_not_empty_GConst :: GeniVal -> Bool
- NLP.GenI.GeniVal: replaceMapG :: Subst -> GeniVal -> GeniVal
- NLP.GenI.GeniVal: replaceOne :: (DescendGeniVal a) => (String, GeniVal) -> a -> a
- NLP.GenI.GeniVal: replaceOneG :: (String, GeniVal) -> GeniVal -> GeniVal
- NLP.GenI.GeniVal: unifyOne :: GeniVal -> GeniVal -> UnificationResult
- NLP.GenI.Morphology: LemmaPlus :: String -> Flist -> LemmaPlus
- NLP.GenI.Morphology: data LemmaPlus
- NLP.GenI.Morphology: lpFeats :: LemmaPlus -> Flist
- NLP.GenI.Morphology: lpLemma :: LemmaPlus -> String
- NLP.GenI.Morphology: type LemmaPlusSentence = [LemmaPlus]
- NLP.GenI.Morphology: type MorphFn = Pred -> Maybe Flist
- NLP.GenI.OptimalityTheory: instance [overlap ok] Eq LexItem
- NLP.GenI.OptimalityTheory: instance [overlap ok] Eq OtConstraint
- NLP.GenI.OptimalityTheory: instance [overlap ok] Eq OtViolation
- NLP.GenI.OptimalityTheory: instance [overlap ok] Eq RankedOtConstraint
- NLP.GenI.OptimalityTheory: instance [overlap ok] Eq RankedOtConstraint2
- NLP.GenI.OptimalityTheory: instance [overlap ok] JSON OtConstraint
- NLP.GenI.OptimalityTheory: instance [overlap ok] JSON OtViolation
- NLP.GenI.OptimalityTheory: instance [overlap ok] JSON RankedOtConstraint
- NLP.GenI.OptimalityTheory: instance [overlap ok] Ord LexItem
- NLP.GenI.OptimalityTheory: instance [overlap ok] Ord OtViolation
- NLP.GenI.OptimalityTheory: instance [overlap ok] Ord RankedOtConstraint
- NLP.GenI.OptimalityTheory: instance [overlap ok] Ord RankedOtConstraint2
- NLP.GenI.OptimalityTheory: instance [overlap ok] Show LexItem
- NLP.GenI.OptimalityTheory: instance [overlap ok] Show OtConstraint
- NLP.GenI.OptimalityTheory: instance [overlap ok] Show OtViolation
- NLP.GenI.OptimalityTheory: instance [overlap ok] Show RankedOtConstraint
- NLP.GenI.Polarity: detectPolFeatures :: [TagElem] -> [String]
- NLP.GenI.Polarity: instance [overlap ok] (ShowLite a) => ShowLite [a]
- NLP.GenI.Polarity: instance [overlap ok] (ShowLite a, ShowLite b) => ShowLite (a, b)
- NLP.GenI.Polarity: instance [overlap ok] Eq PolState
- NLP.GenI.Polarity: instance [overlap ok] Ord PolState
- NLP.GenI.Polarity: instance [overlap ok] Show PolState
- NLP.GenI.Polarity: instance [overlap ok] ShowLite Char
- NLP.GenI.Polarity: instance [overlap ok] ShowLite Int
- NLP.GenI.Polarity: instance [overlap ok] ShowLite TagElem
- NLP.GenI.Polarity: showLite :: (ShowLite a) => a -> String
- NLP.GenI.Polarity: showLitePm :: PolMap -> String
- NLP.GenI.Polarity: showPolPaths :: BitVector -> String
- NLP.GenI.Polarity: showPolPaths' :: BitVector -> Int -> [Int]
- NLP.GenI.Polarity: type PolResult = ([AutDebug], PolAut, PolAut, Sem)
- NLP.GenI.PolarityTypes: PolarityKey :: String -> PolarityKey
- NLP.GenI.PolarityTypes: RestrictedPolarityAttr :: String -> String -> PolarityAttr
- NLP.GenI.PolarityTypes: SimplePolarityAttr :: String -> PolarityAttr
- NLP.GenI.PolarityTypes: _rpkCat :: PolarityAttr -> String
- NLP.GenI.PolarityTypes: data PolarityAttr
- NLP.GenI.PolarityTypes: fromPolarityKey :: PolarityKey -> String
- NLP.GenI.PolarityTypes: instance [overlap ok] Data PolarityKey
- NLP.GenI.PolarityTypes: instance [overlap ok] Eq PolarityAttr
- NLP.GenI.PolarityTypes: instance [overlap ok] Eq PolarityKey
- NLP.GenI.PolarityTypes: instance [overlap ok] Ord PolarityAttr
- NLP.GenI.PolarityTypes: instance [overlap ok] Ord PolarityKey
- NLP.GenI.PolarityTypes: instance [overlap ok] Show PolarityAttr
- NLP.GenI.PolarityTypes: instance [overlap ok] Show PolarityKey
- NLP.GenI.PolarityTypes: instance [overlap ok] Typeable PolarityAttr
- NLP.GenI.PolarityTypes: instance [overlap ok] Typeable PolarityKey
- NLP.GenI.PolarityTypes: newtype PolarityKey
- NLP.GenI.PolarityTypes: readPolarityAttrs :: String -> Set PolarityAttr
- NLP.GenI.PolarityTypes: rpkAtt :: PolarityAttr -> String
- NLP.GenI.PolarityTypes: spkAtt :: PolarityAttr -> String
- NLP.GenI.Simple.SimpleBuilder: instance [overlap ok] Biplate (String, UninflectedDisjunction) GeniVal
- NLP.GenI.Simple.SimpleBuilder: instance [overlap ok] Biplate SimpleGuiItem GeniVal
- NLP.GenI.Simple.SimpleBuilder: instance [overlap ok] Biplate SimpleItem GeniVal
- NLP.GenI.Simple.SimpleBuilder: instance [overlap ok] Data SimpleGuiItem
- NLP.GenI.Simple.SimpleBuilder: instance [overlap ok] DescendGeniVal (String, UninflectedDisjunction)
- NLP.GenI.Simple.SimpleBuilder: instance [overlap ok] DescendGeniVal SimpleGuiItem
- NLP.GenI.Simple.SimpleBuilder: instance [overlap ok] DescendGeniVal SimpleItem
- NLP.GenI.Simple.SimpleBuilder: instance [overlap ok] IafAble SimpleItem
- NLP.GenI.Simple.SimpleBuilder: instance [overlap ok] Show GenerationPhase
- NLP.GenI.Simple.SimpleBuilder: instance [overlap ok] Show SimpleGuiItem
- NLP.GenI.Simple.SimpleBuilder: instance [overlap ok] Show SimpleItem
- NLP.GenI.Simple.SimpleBuilder: instance [overlap ok] Show SimpleStatus
- NLP.GenI.Simple.SimpleBuilder: instance [overlap ok] Typeable SimpleGuiItem
- NLP.GenI.Simple.SimpleBuilder: siAccesible :: SimpleItem -> [String]
- NLP.GenI.Simple.SimpleBuilder: siFoot :: SimpleItem -> Maybe TagSite
- NLP.GenI.Simple.SimpleBuilder: siInaccessible :: SimpleItem -> [String]
- NLP.GenI.Simple.SimpleBuilder: siLeaves :: SimpleItem -> [(String, UninflectedDisjunction)]
- NLP.GenI.Simple.SimpleBuilder: siRoot :: SimpleItem -> TagSite
- NLP.GenI.Simple.SimpleBuilder: simpleBuilder_1p :: SimpleBuilder
- NLP.GenI.Simple.SimpleBuilder: simpleBuilder_2p :: SimpleBuilder
- NLP.GenI.Statistics: instance [overlap ok] JSON Statistics
- NLP.GenI.Statistics: instance [overlap ok] Show Metric
- NLP.GenI.Tags: DerivationStep :: Char -> String -> String -> String -> DerivationStep
- NLP.GenI.Tags: TE :: String -> String -> Integer -> Ptype -> Tree GNode -> Sem -> Map PolarityKey (Int, Int) -> Flist -> [String] -> [SemPols] -> TagElem
- NLP.GenI.Tags: TagSite :: String -> Flist -> Flist -> String -> TagSite
- NLP.GenI.Tags: addToTags :: Tags -> String -> TagElem -> Tags
- NLP.GenI.Tags: class TagItem t
- NLP.GenI.Tags: collect :: (Collectable a) => a -> Set String -> Set String
- NLP.GenI.Tags: data DerivationStep
- NLP.GenI.Tags: data TagElem
- NLP.GenI.Tags: data TagSite
- NLP.GenI.Tags: detectSites :: Tree GNode -> ([TagSite], [TagSite], [TagSite])
- NLP.GenI.Tags: dsChild :: DerivationStep -> String
- NLP.GenI.Tags: dsOp :: DerivationStep -> Char
- NLP.GenI.Tags: dsParent :: DerivationStep -> String
- NLP.GenI.Tags: dsParentSite :: DerivationStep -> String
- NLP.GenI.Tags: emptyTE :: TagElem
- NLP.GenI.Tags: idname :: TagElem -> String
- NLP.GenI.Tags: instance [overlap ok] Biplate (Maybe TagSite) GeniVal
- NLP.GenI.Tags: instance [overlap ok] Biplate TagElem GeniVal
- NLP.GenI.Tags: instance [overlap ok] Biplate TagSite GeniVal
- NLP.GenI.Tags: instance [overlap ok] Collectable TagElem
- NLP.GenI.Tags: instance [overlap ok] Data TagElem
- NLP.GenI.Tags: instance [overlap ok] Data TagSite
- NLP.GenI.Tags: instance [overlap ok] DescendGeniVal TagElem
- NLP.GenI.Tags: instance [overlap ok] DescendGeniVal TagSite
- NLP.GenI.Tags: instance [overlap ok] Eq DerivationStep
- NLP.GenI.Tags: instance [overlap ok] Eq TagElem
- NLP.GenI.Tags: instance [overlap ok] Eq TagSite
- NLP.GenI.Tags: instance [overlap ok] Idable TagElem
- NLP.GenI.Tags: instance [overlap ok] JSON DerivationStep
- NLP.GenI.Tags: instance [overlap ok] Ord DerivationStep
- NLP.GenI.Tags: instance [overlap ok] Ord TagElem
- NLP.GenI.Tags: instance [overlap ok] Ord TagSite
- NLP.GenI.Tags: instance [overlap ok] Show DerivationStep
- NLP.GenI.Tags: instance [overlap ok] Show TagElem
- NLP.GenI.Tags: instance [overlap ok] Show TagSite
- NLP.GenI.Tags: instance [overlap ok] TagItem TagElem
- NLP.GenI.Tags: instance [overlap ok] Typeable TagElem
- NLP.GenI.Tags: instance [overlap ok] Typeable TagSite
- NLP.GenI.Tags: mapBySem :: (TagItem t) => [t] -> Map Pred [t]
- NLP.GenI.Tags: setTidnums :: [TagElem] -> [TagElem]
- NLP.GenI.Tags: showTagSites :: [TagSite] -> String
- NLP.GenI.Tags: subsumedBy :: Sem -> Pred -> Bool
- NLP.GenI.Tags: tagLeaves :: TagElem -> [(String, UninflectedDisjunction)]
- NLP.GenI.Tags: tgIdName :: (TagItem t) => t -> String
- NLP.GenI.Tags: tgIdNum :: (TagItem t) => t -> Integer
- NLP.GenI.Tags: tgSemantics :: (TagItem t) => t -> Sem
- NLP.GenI.Tags: tidnum :: TagElem -> Integer
- NLP.GenI.Tags: tinterface :: TagElem -> Flist
- NLP.GenI.Tags: tpolarities :: TagElem -> Map PolarityKey (Int, Int)
- NLP.GenI.Tags: tsDown :: TagSite -> Flist
- NLP.GenI.Tags: tsName :: TagSite -> String
- NLP.GenI.Tags: tsOrigin :: TagSite -> String
- NLP.GenI.Tags: tsUp :: TagSite -> Flist
- NLP.GenI.Tags: ts_rootFeatureMismatch :: Flist -> String
- NLP.GenI.Tags: ts_semIncomplete :: [Pred] -> String
- NLP.GenI.Tags: ts_synIncomplete :: String
- NLP.GenI.Tags: ts_tbUnificationFailure :: String
- NLP.GenI.Tags: tsemantics :: TagElem -> Sem
- NLP.GenI.Tags: tsempols :: TagElem -> [SemPols]
- NLP.GenI.Tags: ttrace :: TagElem -> [String]
- NLP.GenI.Tags: ttree :: TagElem -> Tree GNode
- NLP.GenI.Tags: ttreename :: TagElem -> String
- NLP.GenI.Tags: ttype :: TagElem -> Ptype
- NLP.GenI.Tags: type TagDerivation = [DerivationStep]
- NLP.GenI.Tags: type Tags = Map String [TagElem]
+ BoolExp: And :: (BoolExp a) -> (BoolExp a) -> BoolExp a
+ BoolExp: Cond :: a -> BoolExp a
+ BoolExp: Not :: (BoolExp a) -> BoolExp a
+ BoolExp: Or :: (BoolExp a) -> (BoolExp a) -> BoolExp a
+ BoolExp: check :: (a -> Bool) -> BoolExp a -> Bool
+ BoolExp: data BoolExp a
+ Data.FullList: (!:) :: Listable l => a -> l a -> FullList a
+ Data.FullList: (++) :: FullList a -> FullList a -> FullList a
+ Data.FullList: class Listable l
+ Data.FullList: data FullList a
+ Data.FullList: fromFL :: FullList a -> [a]
+ Data.FullList: head :: FullList a -> a
+ Data.FullList: indeedFL :: [a] -> w -> (FullList a -> w) -> w
+ Data.FullList: sortNub :: (Eq a, Ord a) => FullList a -> FullList a
+ Data.FullList: tail :: FullList a -> [a]
+ Data.FullList.Internal: (!:) :: Listable l => a -> l a -> FullList a
+ Data.FullList.Internal: (++) :: FullList a -> FullList a -> FullList a
+ Data.FullList.Internal: FullList :: [a] -> FullList a
+ Data.FullList.Internal: class Listable l
+ Data.FullList.Internal: fromFL :: FullList a -> [a]
+ Data.FullList.Internal: head :: FullList a -> a
+ Data.FullList.Internal: indeedFL :: [a] -> w -> (FullList a -> w) -> w
+ Data.FullList.Internal: instance Binary a => Binary (FullList a)
+ Data.FullList.Internal: instance Data a => Data (FullList a)
+ Data.FullList.Internal: instance Eq a => Eq (FullList a)
+ Data.FullList.Internal: instance Functor FullList
+ Data.FullList.Internal: instance Listable FullList
+ Data.FullList.Internal: instance Listable []
+ Data.FullList.Internal: instance NFData a => NFData (FullList a)
+ Data.FullList.Internal: instance Ord a => Ord (FullList a)
+ Data.FullList.Internal: instance Show a => Show (FullList a)
+ Data.FullList.Internal: instance Typeable1 FullList
+ Data.FullList.Internal: newtype FullList a
+ Data.FullList.Internal: sortNub :: (Eq a, Ord a) => FullList a -> FullList a
+ Data.FullList.Internal: tail :: FullList a -> [a]
+ NLP.GenI: BadInputException :: String -> ParseError -> BadInputException
+ NLP.GenI: CompleteResult :: ResultType
+ NLP.GenI: GError :: GeniError -> GeniResult
+ NLP.GenI: GSuccess :: GeniSuccess -> GeniResult
+ NLP.GenI: GeniError :: [Text] -> GeniError
+ NLP.GenI: GeniLexSel :: Text -> [Text] -> GeniLexSel
+ NLP.GenI: GeniResults :: [GeniResult] -> [Text] -> Statistics -> GeniResults
+ NLP.GenI: GeniSuccess :: LemmaPlusSentence -> [Text] -> ResultType -> [Text] -> TagDerivation -> Integer -> [GeniLexSel] -> Int -> [OtViolation] -> GeniSuccess
+ NLP.GenI: PartialResult :: ResultType
+ NLP.GenI: ProgState :: Params -> Macros -> Lexicon -> MorphInputFn -> OtRanking -> [Text] -> ProgState
+ NLP.GenI: class Loadable x
+ NLP.GenI: data BadInputException
+ NLP.GenI: data GeniError
+ NLP.GenI: data GeniLexSel
+ NLP.GenI: data GeniResult
+ NLP.GenI: data GeniResults
+ NLP.GenI: data GeniSuccess
+ NLP.GenI: data ProgState
+ NLP.GenI: data ResultType
+ NLP.GenI: emptyProgState :: Params -> ProgState
+ NLP.GenI: extractResults :: ProgStateRef -> Builder st it Params -> st -> IO [GeniResult]
+ NLP.GenI: getTraces :: ProgState -> Text -> [Text]
+ NLP.GenI: gr :: ProgState -> Macros
+ NLP.GenI: grDerivation :: GeniSuccess -> TagDerivation
+ NLP.GenI: grGlobalWarnings :: GeniResults -> [Text]
+ NLP.GenI: grLemmaSentence :: GeniSuccess -> LemmaPlusSentence
+ NLP.GenI: grLexSelection :: GeniSuccess -> [GeniLexSel]
+ NLP.GenI: grOrigin :: GeniSuccess -> Integer
+ NLP.GenI: grRanking :: GeniSuccess -> Int
+ NLP.GenI: grRealisations :: GeniSuccess -> [Text]
+ NLP.GenI: grResultType :: GeniSuccess -> ResultType
+ NLP.GenI: grResults :: GeniResults -> [GeniResult]
+ NLP.GenI: grStatistics :: GeniResults -> Statistics
+ NLP.GenI: grViolations :: GeniSuccess -> [OtViolation]
+ NLP.GenI: grWarnings :: GeniSuccess -> [Text]
+ NLP.GenI: histogram :: Ord a => [a] -> Map a Int
+ NLP.GenI: initGeni :: ProgStateRef -> SemInput -> IO (Input, GeniWarnings)
+ NLP.GenI: instance Eq GeniError
+ NLP.GenI: instance Eq GeniLexSel
+ NLP.GenI: instance Eq GeniResult
+ NLP.GenI: instance Eq GeniSuccess
+ NLP.GenI: instance Eq ResultType
+ NLP.GenI: instance Exception BadInputException
+ NLP.GenI: instance JSON GeniError
+ NLP.GenI: instance JSON GeniLexSel
+ NLP.GenI: instance JSON GeniResult
+ NLP.GenI: instance JSON GeniSuccess
+ NLP.GenI: instance JSON ResultType
+ NLP.GenI: instance Loadable Lexicon
+ NLP.GenI: instance Loadable Macros
+ NLP.GenI: instance Loadable MorphFnL
+ NLP.GenI: instance Loadable OtRanking
+ NLP.GenI: instance Loadable PreAnchoredL
+ NLP.GenI: instance Loadable TestSuiteL
+ NLP.GenI: instance Loadable TracesL
+ NLP.GenI: instance NFData GeniError
+ NLP.GenI: instance NFData GeniLexSel
+ NLP.GenI: instance NFData GeniResult
+ NLP.GenI: instance NFData GeniSuccess
+ NLP.GenI: instance NFData ResultType
+ NLP.GenI: instance Ord GeniError
+ NLP.GenI: instance Ord GeniLexSel
+ NLP.GenI: instance Ord GeniResult
+ NLP.GenI: instance Ord GeniSuccess
+ NLP.GenI: instance Ord ResultType
+ NLP.GenI: instance Pretty GeniError
+ NLP.GenI: instance Show BadInputException
+ NLP.GenI: instance Typeable BadInputException
+ NLP.GenI: isSuccess :: GeniResult -> Bool
+ NLP.GenI: lParse :: Loadable x => FilePath -> String -> Either ParseError x
+ NLP.GenI: lSet :: Loadable x => x -> ProgState -> ProgState
+ NLP.GenI: lSummarise :: Loadable x => x -> String
+ NLP.GenI: le :: ProgState -> Lexicon
+ NLP.GenI: lemmaSentenceString :: GeniSuccess -> Text
+ NLP.GenI: loadEverything :: ProgStateRef -> IO ()
+ NLP.GenI: loadFromString :: Loadable a => ProgStateRef -> String -> String -> IO a
+ NLP.GenI: loadGeniMacros :: ProgStateRef -> IO Macros
+ NLP.GenI: loadLexicon :: ProgStateRef -> IO Lexicon
+ NLP.GenI: loadRanking :: ProgStateRef -> IO ()
+ NLP.GenI: loadTestSuite :: ProgStateRef -> IO [TestCase]
+ NLP.GenI: morphinf :: ProgState -> MorphInputFn
+ NLP.GenI: nlTrace :: GeniLexSel -> [Text]
+ NLP.GenI: nlTree :: GeniLexSel -> Text
+ NLP.GenI: pa :: ProgState -> Params
+ NLP.GenI: parseSemInput :: String -> Either ParseError SemInput
+ NLP.GenI: prettyResult :: ProgState -> GeniSuccess -> Text
+ NLP.GenI: ranking :: ProgState -> OtRanking
+ NLP.GenI: runGeni :: ProgStateRef -> SemInput -> Builder st it Params -> IO (GeniResults, st)
+ NLP.GenI: showRealisations :: [String] -> String
+ NLP.GenI: traces :: ProgState -> [Text]
+ NLP.GenI: type LexicalSelector = Macros -> Lexicon -> Sem -> IO LexicalSelection
+ NLP.GenI: type ProgStateRef = IORef ProgState
+ NLP.GenI.Builder: Active :: GenStatus
+ NLP.GenI.Builder: Error :: Text -> GenStatus
+ NLP.GenI.Builder: Filtered :: FilterStatus a
+ NLP.GenI.Builder: Finished :: GenStatus
+ NLP.GenI.Builder: NotFiltered :: a -> FilterStatus a
+ NLP.GenI.Builder: data FilterStatus a
+ NLP.GenI.Builder: data GenStatus
+ NLP.GenI.Builder: instance Collectable UninflectedDisjunction
+ NLP.GenI.Builder: instance Data UninflectedDisjunction
+ NLP.GenI.Builder: instance DescendGeniVal UninflectedDisjunction
+ NLP.GenI.Builder: instance NFData Input
+ NLP.GenI.Builder: instance Typeable UninflectedDisjunction
+ NLP.GenI.Builder: num_iterations, num_comparisons, chart_size :: String
+ NLP.GenI.Builder: type TagDerivation = [DerivationStep]
+ NLP.GenI.Configuration: Params :: GrammarType -> BuilderType -> Maybe MorphRealiser -> Maybe LexicalSelector -> [Flag] -> Params
+ NLP.GenI.Configuration: customMorph :: Params -> Maybe MorphRealiser
+ NLP.GenI.Configuration: customSelector :: Params -> Maybe LexicalSelector
+ NLP.GenI.Configuration: helpOption :: OptDescr Flag
+ NLP.GenI.Configuration: instance IsString YamlLight
+ NLP.GenI.Configuration: instance Read LogFmt
+ NLP.GenI.Configuration: instance Read LogTo
+ NLP.GenI.Configuration: instance Show LogFmt
+ NLP.GenI.Configuration: instance Show LogTo
+ NLP.GenI.Configuration: instance Show LoggerConfig
+ NLP.GenI.Configuration: lexiconOption, macrosOption :: OptDescr Flag
+ NLP.GenI.Configuration: modifyFlagP :: (Eq f, Typeable f, Typeable x) => (x -> f) -> (x -> x) -> Params -> Params
+ NLP.GenI.Configuration: readGlobalConfig :: IO (Maybe YamlLight)
+ NLP.GenI.Configuration: setLoggers :: YamlLight -> IO ()
+ NLP.GenI.Configuration: verboseOption :: OptDescr Flag
+ NLP.GenI.Console: consoleGeni :: ProgStateRef -> IO ()
+ NLP.GenI.Console: instance Typeable MNAME
+ NLP.GenI.Console: loadNextSuite :: ProgStateRef -> (FilePath, Maybe [Text]) -> IO [TestCase]
+ NLP.GenI.FeatureStructure: AvPair :: Text -> a -> AvPair a
+ NLP.GenI.FeatureStructure: alignFeat :: Flist GeniVal -> Flist GeniVal -> [(Text, GeniVal, GeniVal)]
+ NLP.GenI.FeatureStructure: alignFeatH :: Flist GeniVal -> Flist GeniVal -> [(Text, GeniVal, GeniVal)] -> [(Text, GeniVal, GeniVal)]
+ NLP.GenI.FeatureStructure: avAtt :: AvPair a -> Text
+ NLP.GenI.FeatureStructure: avVal :: AvPair a -> a
+ NLP.GenI.FeatureStructure: crushAvPair :: AvPair [GeniVal] -> Maybe (AvPair GeniVal)
+ NLP.GenI.FeatureStructure: crushFlist :: Flist [GeniVal] -> Maybe (Flist GeniVal)
+ NLP.GenI.FeatureStructure: data AvPair a
+ NLP.GenI.FeatureStructure: emptyFeatStruct :: FeatStruct a
+ NLP.GenI.FeatureStructure: fromFeatStruct :: FeatStruct a -> Flist a
+ NLP.GenI.FeatureStructure: instance Binary a => Binary (AvPair a)
+ NLP.GenI.FeatureStructure: instance Collectable a => Collectable (AvPair a)
+ NLP.GenI.FeatureStructure: instance Data a => Data (AvPair a)
+ NLP.GenI.FeatureStructure: instance DescendGeniVal a => DescendGeniVal (String, a)
+ NLP.GenI.FeatureStructure: instance DescendGeniVal v => DescendGeniVal (AvPair v)
+ NLP.GenI.FeatureStructure: instance DescendGeniVal v => DescendGeniVal ([String], Flist v)
+ NLP.GenI.FeatureStructure: instance Eq a => Eq (AvPair a)
+ NLP.GenI.FeatureStructure: instance GeniShow (AvPair GeniVal)
+ NLP.GenI.FeatureStructure: instance GeniShow (FeatStruct GeniVal)
+ NLP.GenI.FeatureStructure: instance GeniShow (Flist GeniVal)
+ NLP.GenI.FeatureStructure: instance NFData a => NFData (AvPair a)
+ NLP.GenI.FeatureStructure: instance Ord a => Ord (AvPair a)
+ NLP.GenI.FeatureStructure: instance Pretty (AvPair GeniVal)
+ NLP.GenI.FeatureStructure: instance Pretty (FeatStruct GeniVal)
+ NLP.GenI.FeatureStructure: instance Pretty (Flist GeniVal)
+ NLP.GenI.FeatureStructure: instance Typeable1 AvPair
+ NLP.GenI.FeatureStructure: mkFeatStruct :: Flist GeniVal -> FeatStruct GeniVal
+ NLP.GenI.FeatureStructure: sortFlist :: Flist a -> Flist a
+ NLP.GenI.FeatureStructure: type FeatStruct a = Map Text a
+ NLP.GenI.FeatureStructure: type Flist a = [AvPair a]
+ NLP.GenI.FeatureStructure: unifyFeat :: Monad m => Flist GeniVal -> Flist GeniVal -> m (Flist GeniVal, Subst)
+ NLP.GenI.Flag: AdjOpts :: Optimisation
+ NLP.GenI.Flag: BatchDirFlg :: FilePath -> BatchDirFlg
+ NLP.GenI.Flag: BuilderFlg :: BuilderType -> BuilderFlg
+ NLP.GenI.Flag: DetectPolaritiesFlg :: (Set PolarityAttr) -> DetectPolaritiesFlg
+ NLP.GenI.Flag: DisableGuiFlg :: () -> DisableGuiFlg
+ NLP.GenI.Flag: DumpDerivationFlg :: () -> DumpDerivationFlg
+ NLP.GenI.Flag: EarlyDeathFlg :: () -> EarlyDeathFlg
+ NLP.GenI.Flag: Flag :: (x -> f) -> x -> Flag
+ NLP.GenI.Flag: FromStdinFlg :: () -> FromStdinFlg
+ NLP.GenI.Flag: GeniHand :: GrammarType
+ NLP.GenI.Flag: GrammarTypeFlg :: GrammarType -> GrammarTypeFlg
+ NLP.GenI.Flag: HelpFlg :: () -> HelpFlg
+ NLP.GenI.Flag: InstructionsFileFlg :: FilePath -> InstructionsFileFlg
+ NLP.GenI.Flag: LexiconFlg :: FilePath -> LexiconFlg
+ NLP.GenI.Flag: MacrosFlg :: FilePath -> MacrosFlg
+ NLP.GenI.Flag: MaxResultsFlg :: Integer -> MaxResultsFlg
+ NLP.GenI.Flag: MaxStepsFlg :: Integer -> MaxStepsFlg
+ NLP.GenI.Flag: MetricsFlg :: [String] -> MetricsFlg
+ NLP.GenI.Flag: MorphCmdFlg :: String -> MorphCmdFlg
+ NLP.GenI.Flag: MorphInfoFlg :: FilePath -> MorphInfoFlg
+ NLP.GenI.Flag: NoConstraints :: Optimisation
+ NLP.GenI.Flag: NoLoadTestSuiteFlg :: () -> NoLoadTestSuiteFlg
+ NLP.GenI.Flag: OptimisationsFlg :: [Optimisation] -> OptimisationsFlg
+ NLP.GenI.Flag: OutputFileFlg :: String -> OutputFileFlg
+ NLP.GenI.Flag: PartialFlg :: () -> PartialFlg
+ NLP.GenI.Flag: PolOpts :: Optimisation
+ NLP.GenI.Flag: Polarised :: Optimisation
+ NLP.GenI.Flag: PreAnchored :: GrammarType
+ NLP.GenI.Flag: PreCompiled :: GrammarType
+ NLP.GenI.Flag: RankingConstraintsFlg :: FilePath -> RankingConstraintsFlg
+ NLP.GenI.Flag: RootFeatureFlg :: (Flist GeniVal) -> RootFeatureFlg
+ NLP.GenI.Flag: SimpleBuilder :: BuilderType
+ NLP.GenI.Flag: SimpleOnePhaseBuilder :: BuilderType
+ NLP.GenI.Flag: StatsFileFlg :: FilePath -> StatsFileFlg
+ NLP.GenI.Flag: TestCaseFlg :: Text -> TestCaseFlg
+ NLP.GenI.Flag: TestInstructionsFlg :: [Instruction] -> TestInstructionsFlg
+ NLP.GenI.Flag: TestSuiteFlg :: FilePath -> TestSuiteFlg
+ NLP.GenI.Flag: TimeoutFlg :: Int -> TimeoutFlg
+ NLP.GenI.Flag: TracesFlg :: FilePath -> TracesFlg
+ NLP.GenI.Flag: VerboseModeFlg :: () -> VerboseModeFlg
+ NLP.GenI.Flag: VersionFlg :: () -> VersionFlg
+ NLP.GenI.Flag: ViewCmdFlg :: String -> ViewCmdFlg
+ NLP.GenI.Flag: WeirdFlg :: String -> WeirdFlg
+ NLP.GenI.Flag: data BuilderType
+ NLP.GenI.Flag: data Flag
+ NLP.GenI.Flag: data GrammarType
+ NLP.GenI.Flag: data Optimisation
+ NLP.GenI.Flag: deleteFlag :: (Typeable f, Typeable x) => (x -> f) -> [Flag] -> [Flag]
+ NLP.GenI.Flag: getAllFlags :: (Typeable f, Typeable x) => (x -> f) -> [Flag] -> [x]
+ NLP.GenI.Flag: getFlag :: (Typeable f, Typeable x) => (x -> f) -> [Flag] -> Maybe x
+ NLP.GenI.Flag: hasFlag :: (Typeable f, Typeable x) => (x -> f) -> [Flag] -> Bool
+ NLP.GenI.Flag: instance Eq BatchDirFlg
+ NLP.GenI.Flag: instance Eq BuilderFlg
+ NLP.GenI.Flag: instance Eq BuilderType
+ NLP.GenI.Flag: instance Eq DetectPolaritiesFlg
+ NLP.GenI.Flag: instance Eq DisableGuiFlg
+ NLP.GenI.Flag: instance Eq DumpDerivationFlg
+ NLP.GenI.Flag: instance Eq EarlyDeathFlg
+ NLP.GenI.Flag: instance Eq Flag
+ NLP.GenI.Flag: instance Eq FromStdinFlg
+ NLP.GenI.Flag: instance Eq GrammarType
+ NLP.GenI.Flag: instance Eq GrammarTypeFlg
+ NLP.GenI.Flag: instance Eq HelpFlg
+ NLP.GenI.Flag: instance Eq InstructionsFileFlg
+ NLP.GenI.Flag: instance Eq LexiconFlg
+ NLP.GenI.Flag: instance Eq MacrosFlg
+ NLP.GenI.Flag: instance Eq MaxResultsFlg
+ NLP.GenI.Flag: instance Eq MaxStepsFlg
+ NLP.GenI.Flag: instance Eq MetricsFlg
+ NLP.GenI.Flag: instance Eq MorphCmdFlg
+ NLP.GenI.Flag: instance Eq MorphInfoFlg
+ NLP.GenI.Flag: instance Eq NoLoadTestSuiteFlg
+ NLP.GenI.Flag: instance Eq Optimisation
+ NLP.GenI.Flag: instance Eq OptimisationsFlg
+ NLP.GenI.Flag: instance Eq OutputFileFlg
+ NLP.GenI.Flag: instance Eq PartialFlg
+ NLP.GenI.Flag: instance Eq RankingConstraintsFlg
+ NLP.GenI.Flag: instance Eq RootFeatureFlg
+ NLP.GenI.Flag: instance Eq StatsFileFlg
+ NLP.GenI.Flag: instance Eq TestCaseFlg
+ NLP.GenI.Flag: instance Eq TestInstructionsFlg
+ NLP.GenI.Flag: instance Eq TestSuiteFlg
+ NLP.GenI.Flag: instance Eq TimeoutFlg
+ NLP.GenI.Flag: instance Eq TracesFlg
+ NLP.GenI.Flag: instance Eq VerboseModeFlg
+ NLP.GenI.Flag: instance Eq VersionFlg
+ NLP.GenI.Flag: instance Eq ViewCmdFlg
+ NLP.GenI.Flag: instance Eq WeirdFlg
+ NLP.GenI.Flag: instance Show BuilderType
+ NLP.GenI.Flag: instance Show GrammarType
+ NLP.GenI.Flag: instance Show Optimisation
+ NLP.GenI.Flag: instance Typeable BatchDirFlg
+ NLP.GenI.Flag: instance Typeable BuilderFlg
+ NLP.GenI.Flag: instance Typeable BuilderType
+ NLP.GenI.Flag: instance Typeable DetectPolaritiesFlg
+ NLP.GenI.Flag: instance Typeable DisableGuiFlg
+ NLP.GenI.Flag: instance Typeable DumpDerivationFlg
+ NLP.GenI.Flag: instance Typeable EarlyDeathFlg
+ NLP.GenI.Flag: instance Typeable Flag
+ NLP.GenI.Flag: instance Typeable FromStdinFlg
+ NLP.GenI.Flag: instance Typeable GrammarType
+ NLP.GenI.Flag: instance Typeable GrammarTypeFlg
+ NLP.GenI.Flag: instance Typeable HelpFlg
+ NLP.GenI.Flag: instance Typeable InstructionsFileFlg
+ NLP.GenI.Flag: instance Typeable LexiconFlg
+ NLP.GenI.Flag: instance Typeable MacrosFlg
+ NLP.GenI.Flag: instance Typeable MaxResultsFlg
+ NLP.GenI.Flag: instance Typeable MaxStepsFlg
+ NLP.GenI.Flag: instance Typeable MetricsFlg
+ NLP.GenI.Flag: instance Typeable MorphCmdFlg
+ NLP.GenI.Flag: instance Typeable MorphInfoFlg
+ NLP.GenI.Flag: instance Typeable NoLoadTestSuiteFlg
+ NLP.GenI.Flag: instance Typeable Optimisation
+ NLP.GenI.Flag: instance Typeable OptimisationsFlg
+ NLP.GenI.Flag: instance Typeable OutputFileFlg
+ NLP.GenI.Flag: instance Typeable PartialFlg
+ NLP.GenI.Flag: instance Typeable RankingConstraintsFlg
+ NLP.GenI.Flag: instance Typeable RootFeatureFlg
+ NLP.GenI.Flag: instance Typeable StatsFileFlg
+ NLP.GenI.Flag: instance Typeable TestCaseFlg
+ NLP.GenI.Flag: instance Typeable TestInstructionsFlg
+ NLP.GenI.Flag: instance Typeable TestSuiteFlg
+ NLP.GenI.Flag: instance Typeable TimeoutFlg
+ NLP.GenI.Flag: instance Typeable TracesFlg
+ NLP.GenI.Flag: instance Typeable VerboseModeFlg
+ NLP.GenI.Flag: instance Typeable VersionFlg
+ NLP.GenI.Flag: instance Typeable ViewCmdFlg
+ NLP.GenI.Flag: instance Typeable WeirdFlg
+ NLP.GenI.Flag: isFlag :: (Typeable f, Typeable x) => (x -> f) -> Flag -> Bool
+ NLP.GenI.Flag: modifyFlag :: (Eq f, Typeable f, Typeable x) => (x -> f) -> (x -> x) -> [Flag] -> [Flag]
+ NLP.GenI.Flag: newtype BatchDirFlg
+ NLP.GenI.Flag: newtype BuilderFlg
+ NLP.GenI.Flag: newtype DetectPolaritiesFlg
+ NLP.GenI.Flag: newtype DisableGuiFlg
+ NLP.GenI.Flag: newtype DumpDerivationFlg
+ NLP.GenI.Flag: newtype EarlyDeathFlg
+ NLP.GenI.Flag: newtype FromStdinFlg
+ NLP.GenI.Flag: newtype GrammarTypeFlg
+ NLP.GenI.Flag: newtype HelpFlg
+ NLP.GenI.Flag: newtype InstructionsFileFlg
+ NLP.GenI.Flag: newtype LexiconFlg
+ NLP.GenI.Flag: newtype MacrosFlg
+ NLP.GenI.Flag: newtype MaxResultsFlg
+ NLP.GenI.Flag: newtype MaxStepsFlg
+ NLP.GenI.Flag: newtype MetricsFlg
+ NLP.GenI.Flag: newtype MorphCmdFlg
+ NLP.GenI.Flag: newtype MorphInfoFlg
+ NLP.GenI.Flag: newtype NoLoadTestSuiteFlg
+ NLP.GenI.Flag: newtype OptimisationsFlg
+ NLP.GenI.Flag: newtype OutputFileFlg
+ NLP.GenI.Flag: newtype PartialFlg
+ NLP.GenI.Flag: newtype RankingConstraintsFlg
+ NLP.GenI.Flag: newtype RootFeatureFlg
+ NLP.GenI.Flag: newtype StatsFileFlg
+ NLP.GenI.Flag: newtype TestCaseFlg
+ NLP.GenI.Flag: newtype TestInstructionsFlg
+ NLP.GenI.Flag: newtype TestSuiteFlg
+ NLP.GenI.Flag: newtype TimeoutFlg
+ NLP.GenI.Flag: newtype TracesFlg
+ NLP.GenI.Flag: newtype VerboseModeFlg
+ NLP.GenI.Flag: newtype VersionFlg
+ NLP.GenI.Flag: newtype ViewCmdFlg
+ NLP.GenI.Flag: newtype WeirdFlg
+ NLP.GenI.Flag: setFlag :: (Eq f, Typeable f, Typeable x) => (x -> f) -> x -> [Flag] -> [Flag]
+ NLP.GenI.Flag: type Instruction = (FilePath, Maybe [Text])
+ NLP.GenI.General: buckets :: Ord b => (a -> b) -> [a] -> [(b, [a])]
+ NLP.GenI.General: clumpBy :: (a -> Int) -> Int -> [a] -> [[a]]
+ NLP.GenI.General: first3 :: (a -> a2) -> (a, b, c) -> (a2, b, c)
+ NLP.GenI.General: histogram :: Ord a => [a] -> Map a Int
+ NLP.GenI.General: instance Binary Text
+ NLP.GenI.General: instance Eq AlphaNum
+ NLP.GenI.General: instance JSON Text
+ NLP.GenI.General: instance Ord AlphaNum
+ NLP.GenI.General: isGeniIdentLetter :: Char -> Bool
+ NLP.GenI.General: mkLogname :: Typeable a => a -> String
+ NLP.GenI.General: prettyException :: IOException -> String
+ NLP.GenI.General: quoteString :: String -> String
+ NLP.GenI.General: quoteText :: Text -> Text
+ NLP.GenI.General: second3 :: (b -> b2) -> (a, b, c) -> (a, b2, c)
+ NLP.GenI.General: third3 :: (c -> c2) -> (a, b, c) -> (a, b, c2)
+ NLP.GenI.GeniShow: geniKeyword :: Text -> Text -> Text
+ NLP.GenI.GeniShow: geniShowText :: GeniShow a => a -> Text
+ NLP.GenI.GeniShow: geniShowTree :: GeniShow a => Int -> Tree a -> Text
+ NLP.GenI.GeniShow: instance GeniShow a => GeniShow (Tree a)
+ NLP.GenI.GeniVal: SuccessRep2 :: Text -> Text -> GeniVal -> UnificationResult
+ NLP.GenI.GeniVal: allSubsume :: Monad m => [GeniVal] -> [GeniVal] -> m ([GeniVal], Subst)
+ NLP.GenI.GeniVal: appendSubst :: Subst -> Subst -> Subst
+ NLP.GenI.GeniVal: class Collectable a
+ NLP.GenI.GeniVal: class Idable a
+ NLP.GenI.GeniVal: collect :: Collectable a => a -> Map CollectedVar Int -> Map CollectedVar Int
+ NLP.GenI.GeniVal: crushOne :: [GeniVal] -> Maybe GeniVal
+ NLP.GenI.GeniVal: finaliseVars :: (Collectable a, DescendGeniVal a) => Text -> a -> a
+ NLP.GenI.GeniVal: finaliseVarsById :: (Collectable a, DescendGeniVal a, Idable a) => a -> a
+ NLP.GenI.GeniVal: gConstraints :: GeniVal -> Maybe (FullList Text)
+ NLP.GenI.GeniVal: gLabel :: GeniVal -> Maybe Text
+ NLP.GenI.GeniVal: idOf :: Idable a => a -> Integer
+ NLP.GenI.GeniVal: mkGAnon :: GeniVal
+ NLP.GenI.GeniVal: mkGConst :: FullList Text -> GeniVal
+ NLP.GenI.GeniVal: mkGConstNone :: Text -> GeniVal
+ NLP.GenI.GeniVal: mkGVar :: Text -> Maybe (FullList Text) -> GeniVal
+ NLP.GenI.GeniVal: mkGVarNone :: Text -> GeniVal
+ NLP.GenI.GeniVal: singletonVal :: GeniVal -> Maybe Text
+ NLP.GenI.GeniVal: subsumeOne :: GeniVal -> GeniVal -> UnificationResult
+ NLP.GenI.GeniVal.Internal: Failure :: UnificationResult
+ NLP.GenI.GeniVal.Internal: GeniVal :: Maybe Text -> Maybe (FullList Text) -> GeniVal
+ NLP.GenI.GeniVal.Internal: SuccessRep :: Text -> GeniVal -> UnificationResult
+ NLP.GenI.GeniVal.Internal: SuccessRep2 :: Text -> Text -> GeniVal -> UnificationResult
+ NLP.GenI.GeniVal.Internal: SuccessSans :: GeniVal -> UnificationResult
+ NLP.GenI.GeniVal.Internal: allSubsume :: Monad m => [GeniVal] -> [GeniVal] -> m ([GeniVal], Subst)
+ NLP.GenI.GeniVal.Internal: anonymiseSingletons :: (Collectable a, DescendGeniVal a) => a -> a
+ NLP.GenI.GeniVal.Internal: appendSubst :: Subst -> Subst -> Subst
+ NLP.GenI.GeniVal.Internal: class Collectable a
+ NLP.GenI.GeniVal.Internal: class DescendGeniVal a
+ NLP.GenI.GeniVal.Internal: class Idable a
+ NLP.GenI.GeniVal.Internal: collect :: Collectable a => a -> Map CollectedVar Int -> Map CollectedVar Int
+ NLP.GenI.GeniVal.Internal: crushList :: [[GeniVal]] -> Maybe [GeniVal]
+ NLP.GenI.GeniVal.Internal: crushOne :: [GeniVal] -> Maybe GeniVal
+ NLP.GenI.GeniVal.Internal: data GeniVal
+ NLP.GenI.GeniVal.Internal: data UnificationResult
+ NLP.GenI.GeniVal.Internal: descendGeniVal :: DescendGeniVal a => (GeniVal -> GeniVal) -> a -> a
+ NLP.GenI.GeniVal.Internal: finaliseVars :: (Collectable a, DescendGeniVal a) => Text -> a -> a
+ NLP.GenI.GeniVal.Internal: finaliseVarsById :: (Collectable a, DescendGeniVal a, Idable a) => a -> a
+ NLP.GenI.GeniVal.Internal: gConstraints :: GeniVal -> Maybe (FullList Text)
+ NLP.GenI.GeniVal.Internal: gLabel :: GeniVal -> Maybe Text
+ NLP.GenI.GeniVal.Internal: idOf :: Idable a => a -> Integer
+ NLP.GenI.GeniVal.Internal: instance [overlap ok] (Functor f, DescendGeniVal a) => DescendGeniVal (f a)
+ NLP.GenI.GeniVal.Internal: instance [overlap ok] Binary GeniVal
+ NLP.GenI.GeniVal.Internal: instance [overlap ok] Collectable GeniVal
+ NLP.GenI.GeniVal.Internal: instance [overlap ok] Collectable a => Collectable (Maybe a)
+ NLP.GenI.GeniVal.Internal: instance [overlap ok] Collectable a => Collectable [a]
+ NLP.GenI.GeniVal.Internal: instance [overlap ok] Data GeniVal
+ NLP.GenI.GeniVal.Internal: instance [overlap ok] DescendGeniVal GeniVal
+ NLP.GenI.GeniVal.Internal: instance [overlap ok] Eq GeniVal
+ NLP.GenI.GeniVal.Internal: instance [overlap ok] GeniShow GeniVal
+ NLP.GenI.GeniVal.Internal: instance [overlap ok] NFData GeniVal
+ NLP.GenI.GeniVal.Internal: instance [overlap ok] Ord GeniVal
+ NLP.GenI.GeniVal.Internal: instance [overlap ok] Pretty GeniVal
+ NLP.GenI.GeniVal.Internal: instance [overlap ok] Typeable GeniVal
+ NLP.GenI.GeniVal.Internal: intersectConstraints :: Eq a => Maybe (FullList a) -> Maybe (FullList a) -> Maybe (Maybe (FullList a))
+ NLP.GenI.GeniVal.Internal: isAnon :: GeniVal -> Bool
+ NLP.GenI.GeniVal.Internal: isConst :: GeniVal -> Bool
+ NLP.GenI.GeniVal.Internal: isVar :: GeniVal -> Bool
+ NLP.GenI.GeniVal.Internal: mkGAnon :: GeniVal
+ NLP.GenI.GeniVal.Internal: mkGConst :: FullList Text -> GeniVal
+ NLP.GenI.GeniVal.Internal: mkGConstNone :: Text -> GeniVal
+ NLP.GenI.GeniVal.Internal: mkGVar :: Text -> Maybe (FullList Text) -> GeniVal
+ NLP.GenI.GeniVal.Internal: mkGVarNone :: Text -> GeniVal
+ NLP.GenI.GeniVal.Internal: prependToSubst :: (Text, GeniVal) -> Subst -> Subst
+ NLP.GenI.GeniVal.Internal: prettySubst :: Subst -> Text
+ NLP.GenI.GeniVal.Internal: replace :: DescendGeniVal a => Subst -> a -> a
+ NLP.GenI.GeniVal.Internal: replaceList :: DescendGeniVal a => [(Text, GeniVal)] -> a -> a
+ NLP.GenI.GeniVal.Internal: replaceMapG :: Subst -> GeniVal -> GeniVal
+ NLP.GenI.GeniVal.Internal: replaceOne :: DescendGeniVal a => (Text, GeniVal) -> a -> a
+ NLP.GenI.GeniVal.Internal: replaceOneG :: (Text, GeniVal) -> GeniVal -> GeniVal
+ NLP.GenI.GeniVal.Internal: singletonVal :: GeniVal -> Maybe Text
+ NLP.GenI.GeniVal.Internal: subsumeOne :: GeniVal -> GeniVal -> UnificationResult
+ NLP.GenI.GeniVal.Internal: type CollectedVar = (Text, Maybe (FullList Text))
+ NLP.GenI.GeniVal.Internal: type Subst = Map Text GeniVal
+ NLP.GenI.GeniVal.Internal: unify :: Monad m => [GeniVal] -> [GeniVal] -> m ([GeniVal], Subst)
+ NLP.GenI.GeniVal.Internal: unifyHelper :: Monad m => (GeniVal -> GeniVal -> UnificationResult) -> [GeniVal] -> [GeniVal] -> m ([GeniVal], Subst)
+ NLP.GenI.GeniVal.Internal: unifyOne :: GeniVal -> GeniVal -> UnificationResult
+ NLP.GenI.LexicalSelection: LexicalSelection :: [TagElem] -> [LexEntry] -> GeniWarnings -> LexicalSelection
+ NLP.GenI.LexicalSelection: _lemanchor :: Text
+ NLP.GenI.LexicalSelection: chooseCandI :: Sem -> [LexEntry] -> [LexEntry]
+ NLP.GenI.LexicalSelection: combineList :: Sem -> Macros -> LexEntry -> ([LexCombineError], [TagElem])
+ NLP.GenI.LexicalSelection: combineOne :: Sem -> LexEntry -> SchemaTree -> LexCombine [TagElem]
+ NLP.GenI.LexicalSelection: data LexicalSelection
+ NLP.GenI.LexicalSelection: defaultAnchoring :: Macros -> [LexEntry] -> Sem -> LexicalSelection
+ NLP.GenI.LexicalSelection: defaultLexicalChoice :: Lexicon -> Sem -> [LexEntry]
+ NLP.GenI.LexicalSelection: defaultLexicalSelection :: Macros -> Lexicon -> Sem -> LexicalSelection
+ NLP.GenI.LexicalSelection: defaultLexicalSelector :: Macros -> Lexicon -> Sem -> IO LexicalSelection
+ NLP.GenI.LexicalSelection: enrich :: LexEntry -> SchemaTree -> LexCombine SchemaTree
+ NLP.GenI.LexicalSelection: enrichBy :: SchemaTree -> PathEqPair -> LexCombine SchemaTree
+ NLP.GenI.LexicalSelection: enrichFeat :: AvPair GeniVal -> Flist [GeniVal] -> Maybe (Flist [GeniVal], Subst)
+ NLP.GenI.LexicalSelection: lexEquations :: LexEntry -> Writer [LexCombineError] ([AvPair GeniVal], [PathEqPair])
+ NLP.GenI.LexicalSelection: lexTell :: LexCombineError -> LexCombine ()
+ NLP.GenI.LexicalSelection: lsAnchored :: LexicalSelection -> [TagElem]
+ NLP.GenI.LexicalSelection: lsLexEntries :: LexicalSelection -> [LexEntry]
+ NLP.GenI.LexicalSelection: lsWarnings :: LexicalSelection -> GeniWarnings
+ NLP.GenI.LexicalSelection: matchNodeName :: NodePathEqLhs -> SchemaNode -> Bool
+ NLP.GenI.LexicalSelection: matchNodeNameHelper :: Text -> SchemaNode -> Bool
+ NLP.GenI.LexicalSelection: maybeEnrichBy :: SchemaTree -> PathEqPair -> Maybe (SchemaTree, Subst)
+ NLP.GenI.LexicalSelection: mergeSynonyms :: [LexEntry] -> [LexEntry]
+ NLP.GenI.LexicalSelection: missingCoanchors :: LexEntry -> SchemaTree -> [Text]
+ NLP.GenI.LexicalSelection: missingLexEntries :: [TagElem] -> [LexEntry] -> [LexEntry]
+ NLP.GenI.LexicalSelection: seekCoanchor :: NodePathEqLhs -> SchemaTree -> Maybe SchemaNode
+ NLP.GenI.LexicalSelection: setLemAnchors :: Tree (GNode GeniVal) -> Tree (GNode GeniVal)
+ NLP.GenI.LexicalSelection: setOrigin :: Text -> Tree (GNode v) -> Tree (GNode v)
+ NLP.GenI.LexicalSelection: type LexCombine a = MaybeT (Writer [LexCombineError]) a
+ NLP.GenI.LexicalSelection: type LexicalSelector = Macros -> Lexicon -> Sem -> IO LexicalSelection
+ NLP.GenI.LexicalSelection.Types: BoringError :: Text -> LexCombineError
+ NLP.GenI.LexicalSelection.Types: Bottom :: TopBottom
+ NLP.GenI.LexicalSelection.Types: EnrichError :: PathEqLhs -> LexCombineError2
+ NLP.GenI.LexicalSelection.Types: FamilyNotFoundError :: Text -> LexCombineError
+ NLP.GenI.LexicalSelection.Types: PeqFeat :: Text -> TopBottom -> Text -> NodePathEqLhs
+ NLP.GenI.LexicalSelection.Types: PeqInterface :: Text -> PathEqLhs
+ NLP.GenI.LexicalSelection.Types: PeqJust :: NodePathEqLhs -> PathEqLhs
+ NLP.GenI.LexicalSelection.Types: PeqLex :: Text -> NodePathEqLhs
+ NLP.GenI.LexicalSelection.Types: PeqUnknown :: Text -> PathEqLhs
+ NLP.GenI.LexicalSelection.Types: SchemaError :: [Text] -> LexCombineError2 -> LexCombineError
+ NLP.GenI.LexicalSelection.Types: StringError :: Text -> LexCombineError2
+ NLP.GenI.LexicalSelection.Types: Top :: TopBottom
+ NLP.GenI.LexicalSelection.Types: compressLexCombineErrors :: [LexCombineError] -> [LexCombineError]
+ NLP.GenI.LexicalSelection.Types: data LexCombineError
+ NLP.GenI.LexicalSelection.Types: data LexCombineError2
+ NLP.GenI.LexicalSelection.Types: data NodePathEqLhs
+ NLP.GenI.LexicalSelection.Types: data PathEqLhs
+ NLP.GenI.LexicalSelection.Types: data TopBottom
+ NLP.GenI.LexicalSelection.Types: instance Eq LexCombineError
+ NLP.GenI.LexicalSelection.Types: instance Eq LexCombineError2
+ NLP.GenI.LexicalSelection.Types: instance Eq NodePathEqLhs
+ NLP.GenI.LexicalSelection.Types: instance Eq PathEqLhs
+ NLP.GenI.LexicalSelection.Types: instance Eq TopBottom
+ NLP.GenI.LexicalSelection.Types: instance Ord LexCombineError2
+ NLP.GenI.LexicalSelection.Types: instance Ord NodePathEqLhs
+ NLP.GenI.LexicalSelection.Types: instance Ord PathEqLhs
+ NLP.GenI.LexicalSelection.Types: instance Ord TopBottom
+ NLP.GenI.LexicalSelection.Types: instance Poset LexCombineError
+ NLP.GenI.LexicalSelection.Types: instance Poset LexCombineError2
+ NLP.GenI.LexicalSelection.Types: instance Poset PathEqLhs
+ NLP.GenI.LexicalSelection.Types: instance Poset Text
+ NLP.GenI.LexicalSelection.Types: instance Pretty LexCombineError
+ NLP.GenI.LexicalSelection.Types: instance Pretty LexCombineError2
+ NLP.GenI.LexicalSelection.Types: parsePathEq :: Text -> Writer [LexCombineError] PathEqLhs
+ NLP.GenI.LexicalSelection.Types: showLexCombineError :: LexCombineError -> (Text, Text)
+ NLP.GenI.LexicalSelection.Types: showPathEqLhs :: PathEqLhs -> Text
+ NLP.GenI.LexicalSelection.Types: type PathEqPair = (NodePathEqLhs, GeniVal)
+ NLP.GenI.Lexicon: data LexEntry
+ NLP.GenI.Lexicon: fromLexLiteral :: Literal PolValue -> (Literal GeniVal, SemPols)
+ NLP.GenI.Lexicon: fromLexSem :: [Literal PolValue] -> (Sem, [SemPols])
+ NLP.GenI.Lexicon: iequations :: LexEntry -> Flist GeniVal
+ NLP.GenI.Lexicon: ifamname :: LexEntry -> Text
+ NLP.GenI.Lexicon: ifilters :: LexEntry -> Flist GeniVal
+ NLP.GenI.Lexicon: iinterface :: LexEntry -> Flist GeniVal
+ NLP.GenI.Lexicon: iparams :: LexEntry -> [GeniVal]
+ NLP.GenI.Lexicon: isemantics :: LexEntry -> Sem
+ NLP.GenI.Lexicon: isempols :: LexEntry -> [SemPols]
+ NLP.GenI.Lexicon: iword :: LexEntry -> FullList Text
+ NLP.GenI.Lexicon: mkFullLexEntry :: FullList Text -> Text -> [GeniVal] -> Flist GeniVal -> Flist GeniVal -> Flist GeniVal -> Sem -> [SemPols] -> LexEntry
+ NLP.GenI.Lexicon: mkLexEntry :: FullList Text -> Text -> [GeniVal] -> Flist GeniVal -> Flist GeniVal -> Flist GeniVal -> Sem -> LexEntry
+ NLP.GenI.Lexicon: type Lexicon = [LexEntry]
+ NLP.GenI.Lexicon: type PolValue = (GeniVal, Int)
+ NLP.GenI.Lexicon.Internal: LexEntry :: FullList Text -> Text -> [GeniVal] -> Flist GeniVal -> Flist GeniVal -> Flist GeniVal -> Sem -> [SemPols] -> LexEntry
+ NLP.GenI.Lexicon.Internal: data LexEntry
+ NLP.GenI.Lexicon.Internal: fromLexLiteral :: Literal PolValue -> (Literal GeniVal, SemPols)
+ NLP.GenI.Lexicon.Internal: fromLexSem :: [Literal PolValue] -> (Sem, [SemPols])
+ NLP.GenI.Lexicon.Internal: iequations :: LexEntry -> Flist GeniVal
+ NLP.GenI.Lexicon.Internal: ifamname :: LexEntry -> Text
+ NLP.GenI.Lexicon.Internal: ifilters :: LexEntry -> Flist GeniVal
+ NLP.GenI.Lexicon.Internal: iinterface :: LexEntry -> Flist GeniVal
+ NLP.GenI.Lexicon.Internal: instance Binary LexEntry
+ NLP.GenI.Lexicon.Internal: instance Collectable LexEntry
+ NLP.GenI.Lexicon.Internal: instance Data LexEntry
+ NLP.GenI.Lexicon.Internal: instance DescendGeniVal LexEntry
+ NLP.GenI.Lexicon.Internal: instance Eq LexEntry
+ NLP.GenI.Lexicon.Internal: instance GeniShow LexEntry
+ NLP.GenI.Lexicon.Internal: instance GeniShow [LexEntry]
+ NLP.GenI.Lexicon.Internal: instance NFData LexEntry
+ NLP.GenI.Lexicon.Internal: instance Pretty LexEntry
+ NLP.GenI.Lexicon.Internal: instance Typeable LexEntry
+ NLP.GenI.Lexicon.Internal: iparams :: LexEntry -> [GeniVal]
+ NLP.GenI.Lexicon.Internal: isemantics :: LexEntry -> Sem
+ NLP.GenI.Lexicon.Internal: isempols :: LexEntry -> [SemPols]
+ NLP.GenI.Lexicon.Internal: iword :: LexEntry -> FullList Text
+ NLP.GenI.Lexicon.Internal: mkFullLexEntry :: FullList Text -> Text -> [GeniVal] -> Flist GeniVal -> Flist GeniVal -> Flist GeniVal -> Sem -> [SemPols] -> LexEntry
+ NLP.GenI.Lexicon.Internal: mkLexEntry :: FullList Text -> Text -> [GeniVal] -> Flist GeniVal -> Flist GeniVal -> Flist GeniVal -> Sem -> LexEntry
+ NLP.GenI.Lexicon.Internal: type Lexicon = [LexEntry]
+ NLP.GenI.Lexicon.Internal: type PolValue = (GeniVal, Int)
+ NLP.GenI.Main: forceGuiFlag :: Params -> Params
+ NLP.GenI.Main: main :: IO ()
+ NLP.GenI.Main: mainWithState :: ProgState -> IO ()
+ NLP.GenI.Morphology: instance Typeable MNAME
+ NLP.GenI.Morphology.Types: LemmaPlus :: Text -> Flist GeniVal -> LemmaPlus
+ NLP.GenI.Morphology.Types: MorphOutput :: [Text] -> [Text] -> MorphOutput
+ NLP.GenI.Morphology.Types: data LemmaPlus
+ NLP.GenI.Morphology.Types: data MorphOutput
+ NLP.GenI.Morphology.Types: instance Eq LemmaPlus
+ NLP.GenI.Morphology.Types: instance Eq MorphOutput
+ NLP.GenI.Morphology.Types: instance JSON LemmaPlus
+ NLP.GenI.Morphology.Types: instance JSON MorphOutput
+ NLP.GenI.Morphology.Types: instance NFData LemmaPlus
+ NLP.GenI.Morphology.Types: instance NFData MorphOutput
+ NLP.GenI.Morphology.Types: instance Ord LemmaPlus
+ NLP.GenI.Morphology.Types: instance Ord MorphOutput
+ NLP.GenI.Morphology.Types: lpFeats :: LemmaPlus -> Flist GeniVal
+ NLP.GenI.Morphology.Types: lpLemma :: LemmaPlus -> Text
+ NLP.GenI.Morphology.Types: moRealisations :: MorphOutput -> [Text]
+ NLP.GenI.Morphology.Types: moWarnings :: MorphOutput -> [Text]
+ NLP.GenI.Morphology.Types: parsecToJSON :: Monad m => String -> Parser b -> String -> m b
+ NLP.GenI.Morphology.Types: type LemmaPlusSentence = [LemmaPlus]
+ NLP.GenI.Morphology.Types: type MorphInputFn = Literal GeniVal -> Maybe (Flist GeniVal)
+ NLP.GenI.Morphology.Types: type MorphRealiser = [LemmaPlusSentence] -> [MorphOutput]
+ NLP.GenI.OptimalityTheory: instance Eq LexItem
+ NLP.GenI.OptimalityTheory: instance Eq OtConstraint
+ NLP.GenI.OptimalityTheory: instance Eq OtViolation
+ NLP.GenI.OptimalityTheory: instance Eq RankedOtConstraint
+ NLP.GenI.OptimalityTheory: instance Eq RankedOtConstraint2
+ NLP.GenI.OptimalityTheory: instance JSON OtConstraint
+ NLP.GenI.OptimalityTheory: instance JSON OtViolation
+ NLP.GenI.OptimalityTheory: instance JSON RankedOtConstraint
+ NLP.GenI.OptimalityTheory: instance NFData OtConstraint
+ NLP.GenI.OptimalityTheory: instance NFData OtViolation
+ NLP.GenI.OptimalityTheory: instance NFData RankedOtConstraint
+ NLP.GenI.OptimalityTheory: instance Ord LexItem
+ NLP.GenI.OptimalityTheory: instance Ord OtViolation
+ NLP.GenI.OptimalityTheory: instance Ord RankedOtConstraint
+ NLP.GenI.OptimalityTheory: instance Ord RankedOtConstraint2
+ NLP.GenI.OptimalityTheory: instance Pretty OtConstraint
+ NLP.GenI.OptimalityTheory: instance Pretty RankedOtConstraint
+ NLP.GenI.OptimalityTheory: instance Show LexItem
+ NLP.GenI.OptimalityTheory: instance Show OtConstraint
+ NLP.GenI.OptimalityTheory: instance Show OtViolation
+ NLP.GenI.OptimalityTheory: instance Show RankedOtConstraint
+ NLP.GenI.Parser: geniDerivations :: Parser [TestCaseOutput]
+ NLP.GenI.Parser: geniFeats :: GeniValLike v => Parser (Flist v)
+ NLP.GenI.Parser: geniLanguageDef :: LanguageDef ()
+ NLP.GenI.Parser: geniLexicon :: Parser [LexEntry]
+ NLP.GenI.Parser: geniMacros :: Parser [SchemaTree]
+ NLP.GenI.Parser: geniMorphInfo :: Parser [(Text, Flist GeniVal)]
+ NLP.GenI.Parser: geniSemanticInput :: Parser (Sem, Flist GeniVal, [LitConstr])
+ NLP.GenI.Parser: geniSemantics :: Parser Sem
+ NLP.GenI.Parser: geniTagElems :: Parser [TagElem]
+ NLP.GenI.Parser: geniTestSuite :: Parser [TestCase]
+ NLP.GenI.Parser: geniTestSuiteString :: Parser [Text]
+ NLP.GenI.Parser: geniValue :: Parser GeniVal
+ NLP.GenI.Parser: geniWord :: Parser Text
+ NLP.GenI.Parser: geniWords :: Parser Text
+ NLP.GenI.Parser: instance Eq Annotation
+ NLP.GenI.Parser: instance GeniShow SemInputString
+ NLP.GenI.Parser: instance GeniValLike GeniVal
+ NLP.GenI.Parser: instance GeniValLike [GeniVal]
+ NLP.GenI.Parser: parseFromFile :: Parser a -> SourceName -> IO (Either ParseError a)
+ NLP.GenI.Parser: tillEof :: Parser a -> Parser a
+ NLP.GenI.Parser: toSemInputString :: SemInput -> Text -> SemInputString
+ NLP.GenI.Polarity: PolResult :: [AutDebug] -> PolAut -> PolAut -> Sem -> PolResult
+ NLP.GenI.Polarity: data PolResult
+ NLP.GenI.Polarity: instance Eq PolState
+ NLP.GenI.Polarity: instance Ord PolState
+ NLP.GenI.Polarity: instance Show PolState
+ NLP.GenI.Polarity: prFinal :: PolResult -> PolAut
+ NLP.GenI.Polarity: prInitial :: PolResult -> PolAut
+ NLP.GenI.Polarity: prIntermediate :: PolResult -> [AutDebug]
+ NLP.GenI.Polarity: prSem :: PolResult -> Sem
+ NLP.GenI.Polarity: prettyPolPaths :: BitVector -> Text
+ NLP.GenI.Polarity: prettyPolPaths' :: BitVector -> Int -> [Int]
+ NLP.GenI.Polarity: suggestPolFeatures :: [TagElem] -> [Text]
+ NLP.GenI.Polarity.Internal: PD_Just :: [(PolarityKey, Interval)] -> PolarityDetectionResult
+ NLP.GenI.Polarity.Internal: PD_Nothing :: PolarityDetectionResult
+ NLP.GenI.Polarity.Internal: PD_Unconstrained :: (Text, Interval) -> PolarityDetectionResult
+ NLP.GenI.Polarity.Internal: PD_UserError :: String -> PolarityDetectionResult
+ NLP.GenI.Polarity.Internal: __cat__, __idx__ :: Text
+ NLP.GenI.Polarity.Internal: addPols :: [(PolarityKey, Interval)] -> PolMap -> PolMap
+ NLP.GenI.Polarity.Internal: convertUnconstrainedPolarities :: [PolarityKey] -> PolMap -> PolMap
+ NLP.GenI.Polarity.Internal: data PolarityDetectionResult
+ NLP.GenI.Polarity.Internal: detectPolarity :: Int -> PolarityAttr -> FeatStruct GeniVal -> FeatStruct GeniVal -> PolarityDetectionResult
+ NLP.GenI.Polarity.Internal: detectPolsH :: Set PolarityAttr -> TagElem -> [(PolarityKey, Interval)]
+ NLP.GenI.Polarity.Internal: detectRootCompensation :: Set PolarityAttr -> FeatStruct GeniVal -> PolMap
+ NLP.GenI.Polarity.Internal: nubAut :: (Ord ab, Ord st) => NFA st ab -> NFA st ab
+ NLP.GenI.Polarity.Internal: pdResults :: [PolarityDetectionResult] -> [(PolarityKey, Interval)]
+ NLP.GenI.Polarity.Internal: pdToList :: (String -> String) -> PolarityDetectionResult -> [(PolarityKey, Interval)]
+ NLP.GenI.Polarity.Internal: polarityKeys :: [TagElem] -> PolMap -> [PolarityKey]
+ NLP.GenI.Polarity.Internal: substNodes :: TagElem -> [GNode GeniVal]
+ NLP.GenI.Polarity.Internal: substTops :: TagElem -> [Flist GeniVal]
+ NLP.GenI.Polarity.Internal: toZero :: Int -> Interval
+ NLP.GenI.Polarity.Internal: type PolMap = Map PolarityKey Interval
+ NLP.GenI.Polarity.Internal: type SemMap = Map (Literal GeniVal) [TagElem]
+ NLP.GenI.Polarity.Types: PolarityKeyAv :: Text -> Text -> PolarityKey
+ NLP.GenI.Polarity.Types: PolarityKeyStr :: Text -> PolarityKey
+ NLP.GenI.Polarity.Types: PolarityKeyVar :: Text -> PolarityKey
+ NLP.GenI.Polarity.Types: RestrictedPolarityAttr :: Text -> Text -> PolarityAttr
+ NLP.GenI.Polarity.Types: SimplePolarityAttr :: Text -> PolarityAttr
+ NLP.GenI.Polarity.Types: _rpkCat :: PolarityAttr -> Text
+ NLP.GenI.Polarity.Types: data PolarityAttr
+ NLP.GenI.Polarity.Types: data PolarityKey
+ NLP.GenI.Polarity.Types: instance Data PolarityKey
+ NLP.GenI.Polarity.Types: instance Eq PolarityAttr
+ NLP.GenI.Polarity.Types: instance Eq PolarityKey
+ NLP.GenI.Polarity.Types: instance NFData PolarityAttr
+ NLP.GenI.Polarity.Types: instance NFData PolarityKey
+ NLP.GenI.Polarity.Types: instance Ord PolarityAttr
+ NLP.GenI.Polarity.Types: instance Ord PolarityKey
+ NLP.GenI.Polarity.Types: instance Pretty PolarityKey
+ NLP.GenI.Polarity.Types: instance Show PolarityAttr
+ NLP.GenI.Polarity.Types: instance Typeable PolarityAttr
+ NLP.GenI.Polarity.Types: instance Typeable PolarityKey
+ NLP.GenI.Polarity.Types: readPolarityAttrs :: String -> Set PolarityAttr
+ NLP.GenI.Polarity.Types: rpkAtt :: PolarityAttr -> Text
+ NLP.GenI.Polarity.Types: showPolarityAttrs :: Set PolarityAttr -> String
+ NLP.GenI.Polarity.Types: spkAtt :: PolarityAttr -> Text
+ NLP.GenI.Polarity.Types: type SemPols = [Int]
+ NLP.GenI.Pretty: (<+>) :: Text -> Text -> Text
+ NLP.GenI.Pretty: (<>) :: Text -> Text -> Text
+ NLP.GenI.Pretty: above :: Text -> Text -> Text
+ NLP.GenI.Pretty: between :: Text -> Text -> Text -> Text
+ NLP.GenI.Pretty: class Pretty a where pretty = pack . prettyStr prettyStr = unpack . pretty
+ NLP.GenI.Pretty: instance Pretty Int
+ NLP.GenI.Pretty: instance Pretty Integer
+ NLP.GenI.Pretty: instance Pretty String
+ NLP.GenI.Pretty: parens :: Text -> Text
+ NLP.GenI.Pretty: pretty :: Pretty a => a -> Text
+ NLP.GenI.Pretty: prettyCount :: (a -> Text) -> Text -> (a, Int) -> Text
+ NLP.GenI.Pretty: prettyStr :: Pretty a => a -> String
+ NLP.GenI.Pretty: squares :: Text -> Text
+ NLP.GenI.Semantics: Literal :: gv -> gv -> [gv] -> Literal gv
+ NLP.GenI.Semantics: boringLiteral :: Literal GeniVal -> Maybe Text
+ NLP.GenI.Semantics: class HasConstants a
+ NLP.GenI.Semantics: compareOnLiteral :: Ord a => Literal a -> Literal a -> Ordering
+ NLP.GenI.Semantics: constants :: HasConstants a => a -> Int
+ NLP.GenI.Semantics: data Literal gv
+ NLP.GenI.Semantics: emptyLiteral :: Literal GeniVal
+ NLP.GenI.Semantics: instance Binary g => Binary (Literal g)
+ NLP.GenI.Semantics: instance Collectable a => Collectable (Literal a)
+ NLP.GenI.Semantics: instance Data gv => Data (Literal gv)
+ NLP.GenI.Semantics: instance DescendGeniVal a => DescendGeniVal (Literal a)
+ NLP.GenI.Semantics: instance Eq gv => Eq (Literal gv)
+ NLP.GenI.Semantics: instance GeniShow (Literal GeniVal)
+ NLP.GenI.Semantics: instance GeniShow Sem
+ NLP.GenI.Semantics: instance GeniShow SemInput
+ NLP.GenI.Semantics: instance HasConstants (Literal GeniVal)
+ NLP.GenI.Semantics: instance HasConstants GeniVal
+ NLP.GenI.Semantics: instance HasConstants a => HasConstants [a]
+ NLP.GenI.Semantics: instance NFData g => NFData (Literal g)
+ NLP.GenI.Semantics: instance Ord gv => Ord (Literal gv)
+ NLP.GenI.Semantics: instance Pretty (Literal GeniVal)
+ NLP.GenI.Semantics: instance Pretty Sem
+ NLP.GenI.Semantics: instance Pretty SemInput
+ NLP.GenI.Semantics: instance Typeable1 Literal
+ NLP.GenI.Semantics: isInternalHandle :: Text -> Bool
+ NLP.GenI.Semantics: lArgs :: Literal gv -> [gv]
+ NLP.GenI.Semantics: lHandle :: Literal gv -> gv
+ NLP.GenI.Semantics: lPredicate :: Literal gv -> gv
+ NLP.GenI.Semantics: literalCount :: [Literal GeniVal] -> Map Text Int
+ NLP.GenI.Semantics: removeConstraints :: SemInput -> SemInput
+ NLP.GenI.Semantics: sortByAmbiguity :: Sem -> Sem
+ NLP.GenI.Semantics: sortSem :: Ord a => [Literal a] -> [Literal a]
+ NLP.GenI.Semantics: subsumeLiteral :: Literal GeniVal -> Literal GeniVal -> Maybe (Literal GeniVal, Subst)
+ NLP.GenI.Semantics: subsumeSem :: Sem -> Sem -> [(Sem, Subst)]
+ NLP.GenI.Semantics: subsumeSemH :: Sem -> Sem -> [(Sem, Subst)]
+ NLP.GenI.Semantics: type LitConstr = (Literal GeniVal, [Text])
+ NLP.GenI.Semantics: type Sem = [Literal GeniVal]
+ NLP.GenI.Semantics: type SemInput = (Sem, Flist GeniVal, [LitConstr])
+ NLP.GenI.Semantics: unifyLiteral :: Literal GeniVal -> Literal GeniVal -> Maybe (Literal GeniVal, Subst)
+ NLP.GenI.Semantics: unifySem :: Sem -> Sem -> [(Sem, Subst)]
+ NLP.GenI.Semantics: unifySemH :: Sem -> Sem -> [(Sem, Subst)]
+ NLP.GenI.Simple.SimpleBuilder: instance Data SimpleGuiItem
+ NLP.GenI.Simple.SimpleBuilder: instance DescendGeniVal (Text, UninflectedDisjunction)
+ NLP.GenI.Simple.SimpleBuilder: instance DescendGeniVal SimpleItem
+ NLP.GenI.Simple.SimpleBuilder: instance Show GenerationPhase
+ NLP.GenI.Simple.SimpleBuilder: instance Typeable SimpleGuiItem
+ NLP.GenI.Simple.SimpleBuilder: siFoot_ :: SimpleItem -> Maybe NodeName
+ NLP.GenI.Simple.SimpleBuilder: siRoot_ :: SimpleItem -> NodeName
+ NLP.GenI.Simple.SimpleBuilder: simpleBuilder_2p, simpleBuilder_1p :: SimpleBuilder
+ NLP.GenI.Simple.SimpleBuilder: testCanAdjoin :: SimpleItem -> TagSite -> Maybe (TagSite, TagSite, Subst)
+ NLP.GenI.Simple.SimpleBuilder: testEmptySimpleGuiItem :: SimpleGuiItem
+ NLP.GenI.Simple.SimpleBuilder: testIapplyAdjNode :: Bool -> SimpleItem -> SimpleItem -> Maybe SimpleItem
+ NLP.GenI.Statistics: instance JSON Statistics
+ NLP.GenI.Statistics: instance NFData Metric
+ NLP.GenI.Statistics: instance NFData Statistics
+ NLP.GenI.Statistics: instance Show Metric
+ NLP.GenI.Tag: AdjunctionStep :: Text -> Text -> Text -> DerivationStep
+ NLP.GenI.Tag: InitStep :: Text -> DerivationStep
+ NLP.GenI.Tag: SubstitutionStep :: Text -> Text -> Text -> DerivationStep
+ NLP.GenI.Tag: TE :: Text -> Text -> Integer -> Ptype -> Tree (GNode GeniVal) -> Sem -> Map PolarityKey (Int, Int) -> Flist GeniVal -> [Text] -> [SemPols] -> TagElem
+ NLP.GenI.Tag: TagSite :: Text -> Flist GeniVal -> Flist GeniVal -> Text -> TagSite
+ NLP.GenI.Tag: addToTags :: Tags -> String -> TagElem -> Tags
+ NLP.GenI.Tag: class TagItem t
+ NLP.GenI.Tag: collect :: Collectable a => a -> Map CollectedVar Int -> Map CollectedVar Int
+ NLP.GenI.Tag: data DerivationStep
+ NLP.GenI.Tag: data TagElem
+ NLP.GenI.Tag: data TagSite
+ NLP.GenI.Tag: detectSites :: Tree (GNode GeniVal) -> ([NodeName], [NodeName], [NodeName])
+ NLP.GenI.Tag: dsChild :: DerivationStep -> Text
+ NLP.GenI.Tag: dsParent :: DerivationStep -> Maybe Text
+ NLP.GenI.Tag: dsParentSite :: DerivationStep -> Maybe Text
+ NLP.GenI.Tag: getLexeme :: GNode GeniVal -> [Text]
+ NLP.GenI.Tag: idname :: TagElem -> Text
+ NLP.GenI.Tag: instance Collectable TagElem
+ NLP.GenI.Tag: instance Data TagElem
+ NLP.GenI.Tag: instance Data TagSite
+ NLP.GenI.Tag: instance DescendGeniVal TagElem
+ NLP.GenI.Tag: instance DescendGeniVal TagSite
+ NLP.GenI.Tag: instance Eq DerivationStep
+ NLP.GenI.Tag: instance Eq TagElem
+ NLP.GenI.Tag: instance Eq TagSite
+ NLP.GenI.Tag: instance GeniShow TagElem
+ NLP.GenI.Tag: instance GeniShow [TagElem]
+ NLP.GenI.Tag: instance Idable TagElem
+ NLP.GenI.Tag: instance JSON DerivationStep
+ NLP.GenI.Tag: instance NFData DerivationStep
+ NLP.GenI.Tag: instance NFData TagElem
+ NLP.GenI.Tag: instance Ord DerivationStep
+ NLP.GenI.Tag: instance Ord TagElem
+ NLP.GenI.Tag: instance Ord TagSite
+ NLP.GenI.Tag: instance Pretty [TagSite]
+ NLP.GenI.Tag: instance Show DerivationStep
+ NLP.GenI.Tag: instance TagItem TagElem
+ NLP.GenI.Tag: instance Typeable TagElem
+ NLP.GenI.Tag: instance Typeable TagSite
+ NLP.GenI.Tag: mapBySem :: TagItem t => [t] -> Map (Literal GeniVal) [t]
+ NLP.GenI.Tag: plugTree :: Tree NodeName -> NodeName -> Tree NodeName -> Tree NodeName
+ NLP.GenI.Tag: setTidnums :: [TagElem] -> [TagElem]
+ NLP.GenI.Tag: spliceTree :: NodeName -> Tree NodeName -> NodeName -> Tree NodeName -> Tree NodeName
+ NLP.GenI.Tag: tagLeaves :: TagElem -> [(NodeName, UninflectedDisjunction)]
+ NLP.GenI.Tag: tgIdName :: TagItem t => t -> Text
+ NLP.GenI.Tag: tgIdNum :: TagItem t => t -> Integer
+ NLP.GenI.Tag: tgSemantics :: TagItem t => t -> Sem
+ NLP.GenI.Tag: tgTree :: TagItem t => t -> Tree (GNode GeniVal)
+ NLP.GenI.Tag: tidnum :: TagElem -> Integer
+ NLP.GenI.Tag: tinterface :: TagElem -> Flist GeniVal
+ NLP.GenI.Tag: toTagSite :: GNode GeniVal -> TagSite
+ NLP.GenI.Tag: tpolarities :: TagElem -> Map PolarityKey (Int, Int)
+ NLP.GenI.Tag: tsDown :: TagSite -> Flist GeniVal
+ NLP.GenI.Tag: tsName :: TagSite -> Text
+ NLP.GenI.Tag: tsOrigin :: TagSite -> Text
+ NLP.GenI.Tag: tsUp :: TagSite -> Flist GeniVal
+ NLP.GenI.Tag: ts_rootFeatureMismatch :: Flist GeniVal -> String
+ NLP.GenI.Tag: ts_semIncomplete :: [Literal GeniVal] -> String
+ NLP.GenI.Tag: ts_synIncomplete, ts_tbUnificationFailure :: String
+ NLP.GenI.Tag: tsemantics :: TagElem -> Sem
+ NLP.GenI.Tag: tsempols :: TagElem -> [SemPols]
+ NLP.GenI.Tag: ttrace :: TagElem -> [Text]
+ NLP.GenI.Tag: ttree :: TagElem -> Tree (GNode GeniVal)
+ NLP.GenI.Tag: ttreename :: TagElem -> Text
+ NLP.GenI.Tag: ttype :: TagElem -> Ptype
+ NLP.GenI.Tag: type TagDerivation = [DerivationStep]
+ NLP.GenI.Tag: type Tags = Map String [TagElem]
+ NLP.GenI.TestSuite: TestCase :: Text -> Text -> SemInput -> [Text] -> TestCase
+ NLP.GenI.TestSuite: data TestCase
+ NLP.GenI.TestSuite: instance GeniShow TestCase
+ NLP.GenI.TestSuite: instance Pretty TestCase
+ NLP.GenI.TestSuite: tcExpected :: TestCase -> [Text]
+ NLP.GenI.TestSuite: tcName :: TestCase -> Text
+ NLP.GenI.TestSuite: tcSem :: TestCase -> SemInput
+ NLP.GenI.TestSuite: tcSemString :: TestCase -> Text
+ NLP.GenI.TreeSchema: Auxiliar :: Ptype
+ NLP.GenI.TreeSchema: Foot :: GType
+ NLP.GenI.TreeSchema: GN :: NodeName -> Flist gv -> Flist gv -> Bool -> [Text] -> GType -> Bool -> Text -> GNode gv
+ NLP.GenI.TreeSchema: Initial :: Ptype
+ NLP.GenI.TreeSchema: Lex :: GType
+ NLP.GenI.TreeSchema: Other :: GType
+ NLP.GenI.TreeSchema: Subs :: GType
+ NLP.GenI.TreeSchema: TT :: [GeniVal] -> Text -> Text -> Flist GeniVal -> Ptype -> Maybe Sem -> [Text] -> Tree a -> Ttree a
+ NLP.GenI.TreeSchema: crushGNode :: GNode [GeniVal] -> Maybe (GNode GeniVal)
+ NLP.GenI.TreeSchema: crushTreeGNode :: Tree (GNode [GeniVal]) -> Maybe (Tree (GNode GeniVal))
+ NLP.GenI.TreeSchema: data GNode gv
+ NLP.GenI.TreeSchema: data GType
+ NLP.GenI.TreeSchema: data Ptype
+ NLP.GenI.TreeSchema: data Ttree a
+ NLP.GenI.TreeSchema: foot :: Tree (GNode a) -> GNode a
+ NLP.GenI.TreeSchema: gCategory :: Flist GeniVal -> Maybe GeniVal
+ NLP.GenI.TreeSchema: gaconstr :: GNode gv -> Bool
+ NLP.GenI.TreeSchema: ganchor :: GNode gv -> Bool
+ NLP.GenI.TreeSchema: gdown :: GNode gv -> Flist gv
+ NLP.GenI.TreeSchema: glexeme :: GNode gv -> [Text]
+ NLP.GenI.TreeSchema: gnname :: GNode gv -> NodeName
+ NLP.GenI.TreeSchema: gnnameIs :: NodeName -> GNode gv -> Bool
+ NLP.GenI.TreeSchema: gorigin :: GNode gv -> Text
+ NLP.GenI.TreeSchema: gtype :: GNode gv -> GType
+ NLP.GenI.TreeSchema: gup :: GNode gv -> Flist gv
+ NLP.GenI.TreeSchema: instance [overlap ok] Binary GType
+ NLP.GenI.TreeSchema: instance [overlap ok] Binary Ptype
+ NLP.GenI.TreeSchema: instance [overlap ok] Binary a => Binary (Ttree a)
+ NLP.GenI.TreeSchema: instance [overlap ok] Binary gv => Binary (GNode gv)
+ NLP.GenI.TreeSchema: instance [overlap ok] Collectable a => Collectable (Tree a)
+ NLP.GenI.TreeSchema: instance [overlap ok] Collectable a => Collectable (Ttree a)
+ NLP.GenI.TreeSchema: instance [overlap ok] Collectable gv => Collectable (GNode gv)
+ NLP.GenI.TreeSchema: instance [overlap ok] Data GType
+ NLP.GenI.TreeSchema: instance [overlap ok] Data Ptype
+ NLP.GenI.TreeSchema: instance [overlap ok] Data a => Data (Ttree a)
+ NLP.GenI.TreeSchema: instance [overlap ok] Data gv => Data (GNode gv)
+ NLP.GenI.TreeSchema: instance [overlap ok] DescendGeniVal a => DescendGeniVal (Map k a)
+ NLP.GenI.TreeSchema: instance [overlap ok] DescendGeniVal v => DescendGeniVal (GNode v)
+ NLP.GenI.TreeSchema: instance [overlap ok] DescendGeniVal v => DescendGeniVal (Ttree v)
+ NLP.GenI.TreeSchema: instance [overlap ok] Eq GType
+ NLP.GenI.TreeSchema: instance [overlap ok] Eq Ptype
+ NLP.GenI.TreeSchema: instance [overlap ok] Eq a => Eq (Ttree a)
+ NLP.GenI.TreeSchema: instance [overlap ok] Eq gv => Eq (GNode gv)
+ NLP.GenI.TreeSchema: instance [overlap ok] GeniShow (GNode GeniVal)
+ NLP.GenI.TreeSchema: instance [overlap ok] GeniShow Ptype
+ NLP.GenI.TreeSchema: instance [overlap ok] GeniShow a => GeniShow (Ttree a)
+ NLP.GenI.TreeSchema: instance [overlap ok] NFData GType
+ NLP.GenI.TreeSchema: instance [overlap ok] NFData Ptype
+ NLP.GenI.TreeSchema: instance [overlap ok] NFData gv => NFData (GNode gv)
+ NLP.GenI.TreeSchema: instance [overlap ok] Pretty (GNode GeniVal)
+ NLP.GenI.TreeSchema: instance [overlap ok] Show GType
+ NLP.GenI.TreeSchema: instance [overlap ok] Show Ptype
+ NLP.GenI.TreeSchema: instance [overlap ok] Typeable GType
+ NLP.GenI.TreeSchema: instance [overlap ok] Typeable Ptype
+ NLP.GenI.TreeSchema: instance [overlap ok] Typeable1 GNode
+ NLP.GenI.TreeSchema: instance [overlap ok] Typeable1 Ttree
+ NLP.GenI.TreeSchema: lexemeAttributes :: [Text]
+ NLP.GenI.TreeSchema: params :: Ttree a -> [GeniVal]
+ NLP.GenI.TreeSchema: pfamily :: Ttree a -> Text
+ NLP.GenI.TreeSchema: pidname :: Ttree a -> Text
+ NLP.GenI.TreeSchema: pinterface :: Ttree a -> Flist GeniVal
+ NLP.GenI.TreeSchema: psemantics :: Ttree a -> Maybe Sem
+ NLP.GenI.TreeSchema: ptrace :: Ttree a -> [Text]
+ NLP.GenI.TreeSchema: ptype :: Ttree a -> Ptype
+ NLP.GenI.TreeSchema: root :: Tree a -> a
+ NLP.GenI.TreeSchema: rootUpd :: Tree a -> a -> Tree a
+ NLP.GenI.TreeSchema: setAnchor :: FullList Text -> Tree (GNode a) -> Tree (GNode a)
+ NLP.GenI.TreeSchema: setLexeme :: [Text] -> Tree (GNode a) -> Tree (GNode a)
+ NLP.GenI.TreeSchema: showLexeme :: [Text] -> Text
+ NLP.GenI.TreeSchema: tree :: Ttree a -> Tree a
+ NLP.GenI.TreeSchema: type Macros = [SchemaTree]
+ NLP.GenI.TreeSchema: type NodeName = Text
+ NLP.GenI.TreeSchema: type SchemaNode = GNode [GeniVal]
+ NLP.GenI.TreeSchema: type SchemaTree = Ttree SchemaNode
+ NLP.GenI.Warning: CustomLexWarning :: Text -> GeniWarning
+ NLP.GenI.Warning: LexCombineAllSchemataFailed :: LexWarning
+ NLP.GenI.Warning: LexCombineOneSchemaFailed :: LexCombineError -> LexWarning
+ NLP.GenI.Warning: LexWarning :: [LexEntry] -> LexWarning -> GeniWarning
+ NLP.GenI.Warning: MissingCoanchors :: Text -> Int -> LexWarning
+ NLP.GenI.Warning: MorphWarning :: [Text] -> GeniWarning
+ NLP.GenI.Warning: NoLexSelection :: [Literal GeniVal] -> GeniWarning
+ NLP.GenI.Warning: data GeniWarning
+ NLP.GenI.Warning: data GeniWarnings
+ NLP.GenI.Warning: data LexWarning
+ NLP.GenI.Warning: fromGeniWarnings :: GeniWarnings -> [GeniWarning]
+ NLP.GenI.Warning: mkGeniWarnings :: [GeniWarning] -> GeniWarnings
+ NLP.GenI.Warning: showGeniWarning :: GeniWarning -> [Text]
+ NLP.GenI.Warning: sortWarnings :: GeniWarnings -> GeniWarnings
+ NLP.GenI.Warning.Internal: CustomLexWarning :: Text -> GeniWarning
+ NLP.GenI.Warning.Internal: GeniWarnings :: [GeniWarning] -> GeniWarnings
+ NLP.GenI.Warning.Internal: LexCombineAllSchemataFailed :: LexWarning
+ NLP.GenI.Warning.Internal: LexCombineOneSchemaFailed :: LexCombineError -> LexWarning
+ NLP.GenI.Warning.Internal: LexWarning :: [LexEntry] -> LexWarning -> GeniWarning
+ NLP.GenI.Warning.Internal: MissingCoanchors :: Text -> Int -> LexWarning
+ NLP.GenI.Warning.Internal: MorphWarning :: [Text] -> GeniWarning
+ NLP.GenI.Warning.Internal: NoLexSelection :: [Literal GeniVal] -> GeniWarning
+ NLP.GenI.Warning.Internal: appendWarning :: GeniWarning -> [GeniWarning] -> [GeniWarning]
+ NLP.GenI.Warning.Internal: data GeniWarning
+ NLP.GenI.Warning.Internal: data LexWarning
+ NLP.GenI.Warning.Internal: fromGeniWarnings :: GeniWarnings -> [GeniWarning]
+ NLP.GenI.Warning.Internal: instance Eq GeniWarning
+ NLP.GenI.Warning.Internal: instance Eq LexWarning
+ NLP.GenI.Warning.Internal: instance Monoid GeniWarnings
+ NLP.GenI.Warning.Internal: instance Poset GeniWarning
+ NLP.GenI.Warning.Internal: instance Poset LexWarning
+ NLP.GenI.Warning.Internal: mergeWarning :: GeniWarning -> GeniWarning -> Maybe GeniWarning
+ NLP.GenI.Warning.Internal: mkGeniWarnings :: [GeniWarning] -> GeniWarnings
+ NLP.GenI.Warning.Internal: newtype GeniWarnings
+ NLP.GenI.Warning.Internal: posort :: Poset a => [a] -> [a]
+ NLP.GenI.Warning.Internal: showGeniWarning :: GeniWarning -> [Text]
+ NLP.GenI.Warning.Internal: sortWarnings :: GeniWarnings -> GeniWarnings
+ NLP.GenI.Warning.Internal: toWfCount :: [LexEntry] -> WordFamilyCount
+ NLP.GenI.Warning.Internal: type WordFamilyCount = Map (FullList Text, Text) Int
- NLP.GenI.Builder: (>-->) :: (Monad s) => DispatchFilter s a -> DispatchFilter s a -> DispatchFilter s a
+ NLP.GenI.Builder: (>-->) :: Monad s => DispatchFilter s a -> DispatchFilter s a -> DispatchFilter s a
- NLP.GenI.Builder: Builder :: (Input -> pa -> (st, Statistics)) -> BuilderState st () -> BuilderState st () -> (st -> Bool) -> (st -> [Output]) -> (st -> [Output]) -> Builder st it pa
+ NLP.GenI.Builder: Builder :: (Input -> pa -> (st, Statistics)) -> BuilderState st () -> BuilderState st () -> (st -> GenStatus) -> (st -> [Output]) -> (st -> [Output]) -> Builder st it pa
- NLP.GenI.Builder: Input :: SemInput -> [ILexEntry] -> [(TagElem, BitVector)] -> Input
+ NLP.GenI.Builder: Input :: SemInput -> [LexEntry] -> [(TagElem, BitVector)] -> Input
- NLP.GenI.Builder: UninflectedDisjunction :: [String] -> Flist -> UninflectedDisjunction
+ NLP.GenI.Builder: UninflectedDisjunction :: [Text] -> (Flist GeniVal) -> UninflectedDisjunction
- NLP.GenI.Builder: condFilter :: (Monad s) => (a -> Bool) -> DispatchFilter s a -> DispatchFilter s a -> DispatchFilter s a
+ NLP.GenI.Builder: condFilter :: Monad s => (a -> Bool) -> DispatchFilter s a -> DispatchFilter s a -> DispatchFilter s a
- NLP.GenI.Builder: finished :: Builder st it pa -> st -> Bool
+ NLP.GenI.Builder: finished :: Builder st it pa -> st -> GenStatus
- NLP.GenI.Builder: inLex :: Input -> [ILexEntry]
+ NLP.GenI.Builder: inLex :: Input -> [LexEntry]
- NLP.GenI.Builder: lexicalSelection :: Derivation -> [String]
+ NLP.GenI.Builder: lexicalSelection :: TagDerivation -> [Text]
- NLP.GenI.Builder: preInit :: Input -> Params -> (Input, (Int, Int, Int), PolResult)
+ NLP.GenI.Builder: preInit :: Input -> Params -> (Input, PolResult)
- NLP.GenI.Builder: type DispatchFilter s a = a -> s (Maybe a)
+ NLP.GenI.Builder: type DispatchFilter s a = a -> s (FilterStatus a)
- NLP.GenI.Builder: type Output = (LemmaPlusSentence, Derivation)
+ NLP.GenI.Builder: type Output = (Integer, LemmaPlusSentence, TagDerivation)
- NLP.GenI.Builder: type SemBitMap = Map Pred BitVector
+ NLP.GenI.Builder: type SemBitMap = Map (Literal GeniVal) BitVector
- NLP.GenI.Configuration: getFlagP :: (Show f, Show x, Typeable f, Typeable x) => (x -> f) -> Params -> Maybe x
+ NLP.GenI.Configuration: getFlagP :: (Typeable f, Typeable x) => (x -> f) -> Params -> Maybe x
- NLP.GenI.Configuration: getListFlagP :: (Show f, Show x, Typeable f, Typeable x) => ([x] -> f) -> Params -> [x]
+ NLP.GenI.Configuration: getListFlagP :: (Typeable f, Typeable x) => ([x] -> f) -> Params -> [x]
- NLP.GenI.Configuration: noArg :: (Eq f, Show f, Typeable f) => (() -> f) -> ArgDescr Flag
+ NLP.GenI.Configuration: noArg :: (Eq f, Typeable f) => (() -> f) -> ArgDescr Flag
- NLP.GenI.Configuration: optArg :: (Eq f, Show f, Typeable f, Eq x, Show x, Typeable x) => (x -> f) -> x -> (String -> x) -> String -> ArgDescr Flag
+ NLP.GenI.Configuration: optArg :: (Eq f, Typeable f, Eq x, Typeable x) => (x -> f) -> x -> (String -> x) -> String -> ArgDescr Flag
- NLP.GenI.Configuration: reqArg :: (Eq f, Show f, Typeable f, Eq x, Show x, Typeable x) => (x -> f) -> (String -> x) -> String -> ArgDescr Flag
+ NLP.GenI.Configuration: reqArg :: (Eq f, Typeable f, Eq x, Typeable x) => (x -> f) -> (String -> x) -> String -> ArgDescr Flag
- NLP.GenI.Configuration: setFlagP :: (Eq f, Show f, Show x, Typeable f, Typeable x) => (x -> f) -> x -> Params -> Params
+ NLP.GenI.Configuration: setFlagP :: (Eq f, Typeable f, Typeable x) => (x -> f) -> x -> Params -> Params
- NLP.GenI.General: groupByFM :: (Ord b) => (a -> b) -> [a] -> (Map b [a])
+ NLP.GenI.General: groupByFM :: Ord b => (a -> b) -> [a] -> (Map b [a])
- NLP.GenI.General: insertToListMap :: (Ord b) => b -> a -> Map b [a] -> Map b [a]
+ NLP.GenI.General: insertToListMap :: Ord b => b -> a -> Map b [a] -> Map b [a]
- NLP.GenI.General: isEmptyIntersect :: (Eq a) => [a] -> [a] -> Bool
+ NLP.GenI.General: isEmptyIntersect :: Eq a => [a] -> [a] -> Bool
- NLP.GenI.General: mapMaybeM :: (Monad m) => (a -> m (Maybe b)) -> [a] -> m [b]
+ NLP.GenI.General: mapMaybeM :: Monad m => (a -> m (Maybe b)) -> [a] -> m [b]
- NLP.GenI.GeniShow: class GeniShow a
+ NLP.GenI.GeniShow: class GeniShow a where geniShow = unpack . geniShowText geniShowText = pack . geniShow
- NLP.GenI.GeniShow: geniShow :: (GeniShow a) => a -> String
+ NLP.GenI.GeniShow: geniShow :: GeniShow a => a -> String
- NLP.GenI.GeniVal: SuccessRep :: String -> GeniVal -> UnificationResult
+ NLP.GenI.GeniVal: SuccessRep :: Text -> GeniVal -> UnificationResult
- NLP.GenI.GeniVal: descendGeniVal :: (DescendGeniVal a) => (GeniVal -> GeniVal) -> a -> a
+ NLP.GenI.GeniVal: descendGeniVal :: DescendGeniVal a => (GeniVal -> GeniVal) -> a -> a
- NLP.GenI.GeniVal: replace :: (DescendGeniVal a) => Subst -> a -> a
+ NLP.GenI.GeniVal: replace :: DescendGeniVal a => Subst -> a -> a
- NLP.GenI.GeniVal: replaceList :: (DescendGeniVal a) => [(String, GeniVal)] -> a -> a
+ NLP.GenI.GeniVal: replaceList :: DescendGeniVal a => [(Text, GeniVal)] -> a -> a
- NLP.GenI.GeniVal: type Subst = Map String GeniVal
+ NLP.GenI.GeniVal: type Subst = Map Text GeniVal
- NLP.GenI.GeniVal: unify :: (Monad m) => [GeniVal] -> [GeniVal] -> m ([GeniVal], Subst)
+ NLP.GenI.GeniVal: unify :: Monad m => [GeniVal] -> [GeniVal] -> m ([GeniVal], Subst)
- NLP.GenI.Morphology: attachMorph :: MorphFn -> Sem -> [TagElem] -> [TagElem]
+ NLP.GenI.Morphology: attachMorph :: MorphInputFn -> Sem -> [TagElem] -> [TagElem]
- NLP.GenI.Morphology: inflectSentencesUsingCmd :: String -> [LemmaPlusSentence] -> IO [(LemmaPlusSentence, [String])]
+ NLP.GenI.Morphology: inflectSentencesUsingCmd :: String -> [LemmaPlusSentence] -> IO [(LemmaPlusSentence, MorphOutput)]
- NLP.GenI.Morphology: readMorph :: [(String, [AvPair])] -> MorphFn
+ NLP.GenI.Morphology: readMorph :: [(Text, [AvPair GeniVal])] -> MorphInputFn
- NLP.GenI.Morphology: sansMorph :: LemmaPlusSentence -> [String]
+ NLP.GenI.Morphology: sansMorph :: LemmaPlusSentence -> MorphOutput
- NLP.GenI.Morphology: setMorphAnchor :: GNode -> Tree GNode -> Tree GNode
+ NLP.GenI.Morphology: setMorphAnchor :: GNode GeniVal -> Tree (GNode GeniVal) -> Tree (GNode GeniVal)
- NLP.GenI.Morphology: stripMorphSem :: MorphFn -> Sem -> Sem
+ NLP.GenI.Morphology: stripMorphSem :: MorphInputFn -> Sem -> Sem
- NLP.GenI.OptimalityTheory: NegativeC :: String -> OtConstraint
+ NLP.GenI.OptimalityTheory: NegativeC :: Text -> OtConstraint
- NLP.GenI.OptimalityTheory: NegativeConjC :: [String] -> OtConstraint
+ NLP.GenI.OptimalityTheory: NegativeConjC :: [Text] -> OtConstraint
- NLP.GenI.OptimalityTheory: PositiveC :: String -> OtConstraint
+ NLP.GenI.OptimalityTheory: PositiveC :: Text -> OtConstraint
- NLP.GenI.OptimalityTheory: otWarnings :: Macros -> OtRanking -> [OtViolation] -> [String]
+ NLP.GenI.OptimalityTheory: otWarnings :: Macros -> OtRanking -> [OtViolation] -> [Text]
- NLP.GenI.OptimalityTheory: prettyRank :: Int -> String
+ NLP.GenI.OptimalityTheory: prettyRank :: Int -> Text
- NLP.GenI.OptimalityTheory: prettyViolations :: GetTraces -> Bool -> [OtViolation] -> String
+ NLP.GenI.OptimalityTheory: prettyViolations :: GetTraces -> Bool -> [OtViolation] -> Text
- NLP.GenI.OptimalityTheory: rankResults :: GetTraces -> (a -> Derivation) -> OtRanking -> [a] -> [OtResult a]
+ NLP.GenI.OptimalityTheory: rankResults :: GetTraces -> (a -> TagDerivation) -> OtRanking -> [a] -> [OtResult a]
- NLP.GenI.OptimalityTheory: type GetTraces = String -> [String]
+ NLP.GenI.OptimalityTheory: type GetTraces = Text -> [Text]
- NLP.GenI.Polarity: PolSt :: Int -> [Pred] -> [(Int, Int)] -> PolState
+ NLP.GenI.Polarity: PolSt :: Int -> [Literal GeniVal] -> [(Int, Int)] -> PolState
- NLP.GenI.Polarity: buildAutomaton :: Set PolarityAttr -> Flist -> PolMap -> SemInput -> [TagElem] -> PolResult
+ NLP.GenI.Polarity: buildAutomaton :: Set PolarityAttr -> FeatStruct GeniVal -> PolMap -> SemInput -> [TagElem] -> PolResult
- NLP.GenI.Polarity: declareIdxConstraints :: Flist -> PolMap
+ NLP.GenI.Polarity: declareIdxConstraints :: Flist GeniVal -> PolMap
- NLP.GenI.Polarity: detectIdxConstraints :: Flist -> Flist -> PolMap
+ NLP.GenI.Polarity: detectIdxConstraints :: Flist GeniVal -> Flist GeniVal -> PolMap
- NLP.GenI.Polarity: detectPols :: Set PolarityAttr -> [TagElem] -> [TagElem]
+ NLP.GenI.Polarity: detectPols :: Set PolarityAttr -> TagElem -> TagElem
- NLP.GenI.Polarity: makePolAut :: [TagElem] -> Sem -> PolMap -> PolResult
+ NLP.GenI.Polarity: makePolAut :: [TagElem] -> Sem -> PolMap -> [PolarityKey] -> PolResult
- NLP.GenI.Simple.SimpleBuilder: SimpleGuiItem :: [String] -> [GNode] -> [String] -> Sem -> String -> SimpleGuiItem
+ NLP.GenI.Simple.SimpleBuilder: SimpleGuiItem :: [Text] -> [String] -> Sem -> Text -> SimpleGuiItem
- NLP.GenI.Simple.SimpleBuilder: SimpleItem :: ChartId -> [TagSite] -> [TagSite] -> BitVector -> BitVector -> [String] -> [String] -> [(String, UninflectedDisjunction)] -> Tree String -> TagSite -> Maybe TagSite -> [TagSite] -> TagDerivation -> SimpleGuiItem -> SimpleItem
+ NLP.GenI.Simple.SimpleBuilder: SimpleItem :: ChartId -> [NodeName] -> [NodeName] -> BitVector -> BitVector -> [GNode GeniVal] -> Tree Text -> NodeName -> Maybe NodeName -> [NodeName] -> TagDerivation -> SimpleGuiItem -> SimpleItem
- NLP.GenI.Simple.SimpleBuilder: siAdjnodes :: SimpleItem -> [TagSite]
+ NLP.GenI.Simple.SimpleBuilder: siAdjnodes :: SimpleItem -> [NodeName]
- NLP.GenI.Simple.SimpleBuilder: siDerived :: SimpleItem -> Tree String
+ NLP.GenI.Simple.SimpleBuilder: siDerived :: SimpleItem -> Tree Text
- NLP.GenI.Simple.SimpleBuilder: siHighlight :: SimpleGuiItem -> [String]
+ NLP.GenI.Simple.SimpleBuilder: siHighlight :: SimpleGuiItem -> [Text]
- NLP.GenI.Simple.SimpleBuilder: siIdname :: SimpleGuiItem -> String
+ NLP.GenI.Simple.SimpleBuilder: siIdname :: SimpleGuiItem -> Text
- NLP.GenI.Simple.SimpleBuilder: siNodes :: SimpleGuiItem -> [GNode]
+ NLP.GenI.Simple.SimpleBuilder: siNodes :: SimpleItem -> [GNode GeniVal]
- NLP.GenI.Simple.SimpleBuilder: siPendingTb :: SimpleItem -> [TagSite]
+ NLP.GenI.Simple.SimpleBuilder: siPendingTb :: SimpleItem -> [NodeName]
- NLP.GenI.Simple.SimpleBuilder: siSubstnodes :: SimpleItem -> [TagSite]
+ NLP.GenI.Simple.SimpleBuilder: siSubstnodes :: SimpleItem -> [NodeName]
- NLP.GenI.Statistics: initialStatisticsStateFor :: (MonadState Statistics m) => (m a -> Statistics -> b) -> m a -> b
+ NLP.GenI.Statistics: initialStatisticsStateFor :: MonadState Statistics m => (m a -> Statistics -> b) -> m a -> b
- NLP.GenI.Statistics: type StatisticsState a = forall m. (MonadState Statistics m) => m a
+ NLP.GenI.Statistics: type StatisticsState a = forall m. MonadState Statistics m => m a

Files

GenI.cabal view
@@ -1,5 +1,5 @@ Name:           GenI-Version:        0.20.2+Version:        0.22 License:        GPL License-file:   LICENSE Author:         Carlos Areces and Eric Kow@@ -8,28 +8,28 @@ Description:    A natural language generator (specifically, an FB-LTAG surface realiser) Homepage:       http://projects.haskell.org/GenI Maintainer:     geni-users@loria.fr-Build-Type:     Custom-Cabal-Version: >=1.2.3+Build-Type:     Simple+Cabal-Version: >=1.8 data-files: AUTHORS, INSTALL, README, NEWS, GenI.cabal,             examples/artificial/lexicon,-            examples/artificial/macros,+            examples/artificial/trees,             examples/artificial/suite,             examples/artificial/suite-bad,             examples/chatnoir/lexicon,-            examples/chatnoir/macros,+            examples/chatnoir/trees,             examples/chatnoir/suite,             examples/demo/lexicon,-            examples/demo/macros,+            examples/demo/trees,             examples/demo/README,             examples/demo/suite,             examples/ej/lexicon,-            examples/ej/macros,+            examples/ej/trees,             examples/ej/suite,             examples/nosemantics/lexicon,-            examples/nosemantics/macros,+            examples/nosemantics/trees,             examples/nosemantics/README.txt,             examples/promettre/lexicon,-            examples/promettre/macros,+            examples/promettre/trees,             examples/promettre/morphinfo,             examples/promettre/suite,             examples/xmg-example/grammar/Arguments.mg,@@ -44,93 +44,123 @@             examples/xmg-example/lexicon/demo-morph-utf8.mph,             examples/xmg-example/Makefile,             examples/xmg-example/README,-            examples/xmg-example/suite,-            etc/stupidmorph.pl,-            etc/macstuff/Info.plist,-            etc/macstuff/wxmac.icns--extra-source-files: src/NLP/GenI/SysGeni.hs-                    src/NLP/GenI/Test.hs-                    src/NLP/GenI/Simple/SimpleGui.lhs,-                    src/NLP/GenI/Gui.lhs-                    src/NLP/GenI/GraphvizShow.hs,-                    src/NLP/GenI/GuiHelper.hs-                    src/NLP/GenI/Console.hs,-                    src/NLP/GenI/Graphviz.hs-                    src/NLP/GenI/BuilderGui.lhs,-                    src/NLP/GenI/GraphvizShowPolarity.lhs,-                    src/NLP/GenI/Regression.hs+            examples/xmg-example/suite +extra-source-files: geni-test/NLP/GenI/Test.hs -Flag gui-  description: Build with a graphical user interface-  default: False+source-repository head+  type:     darcs+  location: http://code.haskell.org/GenI  Flag static   Description: Build a static binary   Default:     False  Library-  Build-depends: parsec >= 2 && < 3,-                 base >= 3 && < 4,-                 containers >= 0.1,-                 process > 1,-                 QuickCheck >= 1.2 && < 2,-                 json >= 0.4.3 && < 0.5,-                 HUnit > 1 && < 1.3,-                 mtl > 1.0 && < 1.2,-                 parallel >= 1.1 && < 1.2,-                 binary >= 0.5.0.2 && < 0.6,-                 split >= 0.1.1 && < 0.2,-                 test-framework-hunit >= 0.2.4 && < 0.3,-                 test-framework-quickcheck >= 0.2.4 && < 0.3,-                 test-framework >= 0.2.4 && < 0.3,-                 utf8-string >= 0.3.5 && < 0.4,-                 uniplate >= 1.2.0 && < 1.3--  if !flag(gui)-    cpp-options:      -DDISABLE_GUI+  Build-depends: base >= 4 && < 5+               , binary >= 0.5.0.2+               , bytestring  == 0.9.*+               , cabal-macosx  >= 0.1.2 && < 0.3+               , containers >= 0.1+               , deepseq+               , directory   > 1+               , filepath    == 1.*+               , hslogger == 1.1.*+               , json >= 0.4.3 && < 0.6+               , MaybeT == 0.1.*+               , mtl > 1.0 && < 2.1+               , old-locale+               , ordered == 0.1.*+               , parsec >= 2 && < 3.2+               , process > 1+               , split >= 0.1.1 && < 0.2+               , syb+               , text+               , time >= 1.1 && < 1.3+               , utf8-string >= 0.3.5 && < 0.4+               , yaml-light  == 0.1.*    if flag(static)     ghc-options: -static -optl-static    Exposed-Modules:-                NLP.GenI.Btypes,-                NLP.GenI.BtypesBinary,+                BoolExp,+                Data.FullList.Internal,+                Data.FullList,+                NLP.GenI.Console,+                NLP.GenI.FeatureStructure,+                NLP.GenI.Flag,                 NLP.GenI.General,-                NLP.GenI.GeniParsers,                 NLP.GenI.GeniShow,                 NLP.GenI.GeniVal,-                NLP.GenI.Tags,+                NLP.GenI.GeniVal.Internal,+                NLP.GenI.Lexicon,+                NLP.GenI.Lexicon.Internal,+                NLP.GenI.LexicalSelection,+                NLP.GenI.LexicalSelection.Types,+                NLP.GenI.Main,+                NLP.GenI.Parser,+                NLP.GenI.Pretty,+                NLP.GenI.Semantics,+                NLP.GenI.Tag,+                NLP.GenI.TestSuite,+                NLP.GenI.TreeSchema,+                NLP.GenI.Warning,+                NLP.GenI.Warning.Internal,                 NLP.GenI.Morphology,+                NLP.GenI.Morphology.Types,                 NLP.GenI.OptimalityTheory,                 NLP.GenI.Polarity,-                NLP.GenI.PolarityTypes,+                NLP.GenI.Polarity.Internal,+                NLP.GenI.Polarity.Types,                 NLP.GenI.Automaton,                 NLP.GenI.Statistics,                 NLP.GenI.Builder,                 NLP.GenI.Simple.SimpleBuilder,-                -- NLP.GenI.CkyEarley.CkyBuilder,-                NLP.GenI.Geni, NLP.GenI.Configuration+                NLP.GenI.Configuration,+                NLP.GenI+  Other-Modules:+                Paths_GenI    Hs-Source-Dirs: src-  Extensions:     CPP, Rank2Types, OverlappingInstances, MultiParamTypeClasses, FlexibleContexts, TypeSynonymInstances,  FlexibleInstances, DeriveDataTypeable, ExistentialQuantification, LiberalTypeSynonyms-  Ghc-options:    -Wall -O2+  Ghc-options:    -Wall   Ghc-prof-options: -auto-all  Executable     geni- Main-Is:        MainGeni.lhs- Hs-Source-Dirs: src- Extensions:     CPP, Rank2Types, OverlappingInstances, MultiParamTypeClasses, FlexibleContexts, TypeSynonymInstances,  FlexibleInstances, DeriveDataTypeable, ExistentialQuantification, LiberalTypeSynonyms+ Main-Is:        geni.hs+ Hs-Source-Dirs: geni - Ghc-options:    -Wall -O2+ Ghc-options:    -Wall -rtsopts  Ghc-prof-options: -auto-all- Build-Depends: directory > 1,-                filepath >= 1.1.0 && < 1.2- if flag(gui)-    Build-Depends: wx >= 0.10.3 && < 0.13- else-    cpp-options:      -DDISABLE_GUI+ Build-Depends: base >= 4 && < 5+              , GenI+              , containers  >= 0.1+              , directory   > 1+              , filepath    == 1.*+              , yaml-light  == 0.1.*+              , hslogger    == 1.1.*+              , json        >= 0.4 && < 0.6+              , mtl         > 1.0 && < 2.1+              , process     > 1+              , split       == 0.1.*+              , utf8-string == 0.3.* - if flag(static)-    ghc-options: -static -optl-static+Test-Suite geni-test+ Type:          exitcode-stdio-1.0+ Main-Is:       MainTest.hs+ Hs-Source-Dirs: geni-test+ Build-Depends:    GenI+                 , base >= 4 && < 5+                 , containers  >= 0.1+                 , filepath   == 1.*+                 , json+                 , mtl+                 , parsec >= 2 && < 3.2+                 , QuickCheck == 2.4.*+                 , smallcheck+                 , HUnit > 1 && < 1.3+                 , test-framework-hunit >= 0.2.4 && < 0.3+                 , test-framework-quickcheck2 >= 0.2.4 && < 0.3+                 , test-framework-smallcheck+                 , test-framework > 0.3+                 , text
INSTALL view
@@ -1,13 +1,12 @@ Requirements ------------- * GHC 6.8 or 6.10- * libgmp (for ghc)+ * Haskell Platform 2011.3.0.0  GUI requirements ---------------- Only needed if you want the graphical interface:  * wxWidgets 2.8- * wxHaskell 0.11+ * wxHaskell  * Graphviz  Building GenI@@ -15,7 +14,7 @@ 1. obtain cabal-install 2. run: cabal install 3. if you want the graphical interface, try-    cabal install -fgui+    cabal install ./geni-gui    but ONLY AFTER you succeed in installing the text version :-) -For more details, see http://trac.haskell.org/GenI+For more details, see http://projects.haskell.org/GenI
NEWS view
@@ -1,3 +1,111 @@+GenI 0.22, 14 Apr 2012+----------------------+Note that the changes between this release and 0.20 are considered to be under+the BSD3 license.  GenI overall remains dual-licensed under the GPL and any+commercial-use terms you may wish to negotiate with INRIA. Having secured the+rights to use GenI 0.20, you may freely use GenI 0.22 in a similar fashion.++CHANGES TO WATCH OUT FOR++* Separation of geni and geni-gui into two packages;+  simpler installation+* Now using the top feature for lemanchors instead of bot+* Empty disjunctions forbidden in unification variables+* JSON input/output to morph processors have changed+* Lexical selection unifies semantics of tree schema + lemma with+  input semantics.++GUI++* New results tab with reminder of inputs+* Add gui element to display unanchored lexical selection.+* Jump to new tab in debugger panel when created.+* Update gui to use Pretty instead of Show+* Rename $algo-session tab to "tree assembly"+* Make warnings resizable.+* Fix display of path equations with 'interface' in them.+* Fix #50 - load button has no effect.+* Fix #49 - correct order that leaf nodes are returned.+* Show GenI version in About box.+* Add detect polarities and root feature editor to main gui.++DOCUMENTATION++* Literate GenI and genimanual replaced with+  http://projects.haskell.org/GenI/manual++GENERAL++* Builds with GHC 7+* Core behaviour+     * Early null-adjunction and semfilter obligatory+     * Handling of zero-literal semantic items restored+     * Unconstrained polarities in automaton construction.+       This makes it possible to do polarity detection with only a+       weakly specified root feature like [cat:_], and without needing+       the relevant feature to be implemented everywhere.++* Flags:+     * --trees (used to be --macros; latter is deprecated)+     * --batchdir now optional (defaults to a new temp dir)+     * --maxsteps (stop after N steps)+     * --extrapol REMOVED (use root feature instead)+* Logging facility (not used much in GenI yet)+  Can be configured in ~/.geni/config.yaml, for example+  logging:+   -+     name     : NLP.GenI.Console+     level    : WARN+     format   : simple "$msg"+   -+     name     : NLP.Geni.LexicalSelection+     level    : DEBUG+     format   : simple "$utcTime $loggername $msg"+     handler  : stderr+* Less repetition in warnings (hopefully easier to read)+* More hiding of constructors for safety+* New enrichment option for setting co-anchors (foo.lex=hello)+* Lexical selection performance enhancements+* Variables that only occur once are converted to anonymous,+  should make unification a bit more efficient+* Fix #39: reject malformed root feature input.+* New feature:+  * Variables with constraints on their possible values (?X/foo|bar)+  * Fancy disjunctions: tree schemata now allow disjunctions of+    unification variables (but not recursive). These must flatten down+    to plain old atomic disjunction once converted to elementary trees++* Time metric in statistics (Laura Perez)+* Do top/bottom unification on na-constrained nodes during initialisation.+* Polarity detection relaxed to work with constrained variables too.+  (?X/foo|bar gives the result as foo|bar)+* Bugfix in interpretation of root feature (it should be sorted).+* Flags:+  * --rootfeat always assumed, but defaults to '[cat:_]'+  * '-r' a short command line option for '--rootfeat'.++LIBRARY++* Somewhat safer and easier to understand API+  (still no stability yet)+* Replace String with Text in GeniVal+* Replace Show abuse with custom Pretty class+* Slightly less stateful (no target semantics in state)+* Much rearranging and renaming (sorry!)+* New: ability to provide custom lexical selection action+* New: ability to provide custom morph postprocessing action+* de-haskell98 (Gwern Branwen)+* No more null builder.++TOOLS (darcs get --lazy http://code.haskell.org/GenI)++* new tool, genireport: summarise batch generation results+* geniserver now talks over HTTP using a JSON format+* Use Sylvain Salvati's xmg2geni.xsl instead of geniconvert.+    * xmg2geni: fix treatment of missing lexemes.+    * xmg2geni: treat type=coanchor as other nodes in GenI.+* geniwrapper: illustrates C wrapper of GenI API+ GenI 0.20, 29 Sep 2009 ---------------------- - NON BACKWARD-COMPATIBLE CHANGES
README view
@@ -1,24 +1,27 @@-documentation+Documentation --------------make doc # (pdflatex and haddock are needed)- 1. users manual: -     http://wiki.loria.fr/wiki/GenI-2. semi-literate source code: -     doc/genidoc.pdf -3. API: -     doc/api/index.html+     http://projects.haskell.org/GenI/manual+2. API:+     http://projects.haskell.org/GenI/api-doc -installing GenI+Installing GenI ----------------(tested on Linux and MacOs X)+(tested on Linux, Windows, and MacOS X) -see INSTALL for details+see INSTALL for details (should just be cabal install) -assuming everything above is installed correctly,-it should possible to just make+Development+-----------+The code style has evolved a lot.  Sorry for the inconsistency.+As of 2012-05-06, I'm trying to move to a published style guide+so I can stop thinking about it -contact us!+  https://github.com/tibbe/haskell-style-guide++But the code will take a long time to catch up++Contact us! ----------- Please let us know if you are using GenI; we'd like to hear about your experiences, both positive and negative.
Setup.hs view
@@ -1,117 +1,2 @@-{-# LANGUAGE CPP #-}--import Control.Monad (foldM_, forM_)-import Data.Maybe ( fromMaybe )-import System.Cmd-import System.Exit-import System.Info (os)-import System.FilePath-import System.Directory ( doesFileExist, copyFile, removeFile, createDirectoryIfMissing )--import Distribution.PackageDescription-import Distribution.Simple.Setup import Distribution.Simple-import Distribution.Simple.LocalBuildInfo--#ifndef WIN32-import System.Posix.Files (fileMode, getFileStatus, setFileMode,-                           ownerExecuteMode, groupExecuteMode, otherExecuteMode)-import Data.Bits ( (.|.) )-#endif--main :: IO ()-main = defaultMainWithHooks $ addMacHook simpleUserHooks- where-  addMacHook h =-   case os of-    "darwin" -> h { postInst = appBundleHook } -- is it OK to treat darwin as synonymous with MacOS X?-    _        -> h--appBundleHook :: Args -> InstallFlags -> PackageDescription -> LocalBuildInfo -> IO ()-appBundleHook _ _ pkg localb =- forM_ exes $ \app ->-   do createAppBundle theBindir (buildDir localb </> app </> app)-      customiseAppBundle (appBundlePath theBindir app) app-        `catch` \err -> putStrLn $ "Warning: could not customise bundle for " ++ app ++ ": " ++ show err-      removeFile (theBindir </> app)-      createAppBundleWrapper theBindir app- where-  theBindir = bindir $ absoluteInstallDirs pkg localb NoCopyDest-  exes = fromMaybe (map exeName $ executables pkg) mRestrictTo---- ------------------------------------------------------------------------- helper code for application bundles--- -------------------------------------------------------------------------- | 'createAppBundle' @d p@ - creates an application bundle in @d@---   for program @p@, assuming that @d@ already exists and is a directory.---   Note that only the filename part of @p@ is used.-createAppBundle :: FilePath -> FilePath -> IO ()-createAppBundle dir p =- do createDirectoryIfMissing False $ bundle-    createDirectoryIfMissing True  $ bundleBin-    createDirectoryIfMissing True  $ bundleRsrc-    copyFile p (bundleBin </> takeFileName p)- where-  bundle     = appBundlePath dir p-  bundleBin  = bundle </> "Contents/MacOS"-  bundleRsrc = bundle </> "Contents/Resources"---- | 'createAppBundleWrapper' @d p@ - creates a script in @d@ that calls---   @p@ from the application bundle @d </> takeFileName p <.> "app"@-createAppBundleWrapper :: FilePath -> FilePath -> IO ()-createAppBundleWrapper bindir p =-  do writeFile scriptFile scriptTxt-     makeExecutable scriptFile- where-  scriptFile = bindir </> takeFileName p-  scriptTxt = "`dirname $0`" </> appBundlePath "." p </> "Contents/MacOS" </> takeFileName p ++ " \"$@\""--appBundlePath :: FilePath -> FilePath -> FilePath-appBundlePath dir p = dir </> takeFileName p <.> "app"---- ------------------------------------------------------------------------- utilities--- ------------------------------------------------------------------------makeExecutable :: FilePath -> IO ()-#ifdef WIN32-makeExecutable = const (return ())-#else-makeExecutable f =-  do st <- getFileStatus f-     let m  = fileMode st-         m2 = m .|. ownerExecuteMode .|. groupExecuteMode .|. otherExecuteMode-     setFileMode f m2-#endif---- ------------------------------------------------------------------------- customisations--- -------------------------------------------------------------------------- | Put here IO actions needed to add any fancy things (eg icons)---   you want to your application bundle.-customiseAppBundle :: FilePath -- ^ app bundle path-                   -> FilePath -- ^ full path to original binary-                   -> IO ()-customiseAppBundle bundleDir p =- case takeFileName p of-  "geni" ->-    do hasRez <- doesFileExist "/Developer/Tools/Rez"-       if hasRez-          then do -- set the icon-                  copyFile "etc/macstuff/Info.plist" (bundleDir </> "Contents/Info.plist")-                  copyFile "etc/macstuff/wxmac.icns" (bundleDir </> "Contents/Resources/wxmac.icns")-                  -- no idea what this does-                  system ("/Developer/Tools/Rez -t APPL Carbon.r -o " ++ bundleDir </> "Contents/MacOS/geni")-                  writeFile (bundleDir </> "PkgInfo") "APPL????"-                  -- tell Finder about the icon-                  system ("/Developer/Tools/SetFile -a C " ++ bundleDir </> "Contents")-                  return ()-          else putStrLn "Developer Tools not found.  Too bad; no fancy icons for you."-  ""     -> return ()---- | Put here the list of executables which contain a GUI.  If they all---   contain a GUI (or you don't really care that much), just put Nothing-mRestrictTo :: Maybe [String]-mRestrictTo = Just ["geni"]+main = defaultMain
− etc/macstuff/Info.plist
@@ -1,36 +0,0 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">-<plist version="1.0">-<dict>-	<key>CFBundleDevelopmentRegion</key>-	<string>English</string>-	<key>CFBundleExecutable</key>-	<string>geni</string>-	<key>CFBundleGetInfoString</key>-	<string>GenI</string>-	<key>CFBundleIconFile</key>-	<string>wxmac.icns</string>-	<key>CFBundleIdentifier</key>-	<string>fr.loria.geni</string>-	<key>CFBundleInfoDictionaryVersion</key>-	<string>6.0</string>-	<key>CFBundleLongVersionString</key>-	<string>(c) 2005-2009 LORIA</string>-	<key>CFBundleName</key>-	<string>GenI</string>-	<key>CFBundlePackageType</key>-	<string>APPL</string>-	<key>CFBundleShortVersionString</key>-	<string>0</string>-	<key>CFBundleSignature</key>-	<string>????</string>-	<key>CFBundleVersion</key>-	<string>0</string>-	<key>CSResourcesFileMapped</key>-	<true/>-	<key>LSRequiresCarbon</key>-	<true/>-	<key>NSHumanReadableCopyright</key>-	<string>Copyright 2005-2009 LORIA</string>-</dict>-</plist>
− etc/macstuff/wxmac.icns

binary file changed (46234 → absent bytes)

− etc/stupidmorph.pl
@@ -1,85 +0,0 @@-:-eval 'exec perl -w -S $0 ${1+"$@"}'- if 0; --use strict;-use JSON;--# ---------------------------------------------------------------------# idiotic morphological generator-#-# this outputs for each lemma the name of the lemma and its category-# ----------------------------------------------------------------------# ---------------------------------------------------------------------# from GenI-# ----------------------------------------------------------------------# we return a list of lists of hashes-# - each item in the outer list corresponds to a sentence-# - each item in the inner list corresponds to a word-# - each hash represents the features read from GenI plus a special "__lemma__" feature-#   which holds the lemma-sub read_morph_request {-  my $json_str = shift;-  my $allR = from_json $json_str;-  my @r_sentences = (); # one request per sentence--  foreach my $sentenceR (@$allR) {-    my @r_words = ();-    foreach my $wordR (@$sentenceR) {-      my $lemma = $wordR->{lemma};-      my $featstr = $wordR->{"lemma-features"};-      $featstr =~ s/^\[//;-      $featstr =~ s/\]$//;--      my %feat = ();-      my $av = "";-      for (split(/ /, $featstr)) {-        $av = $_;-        my ($attr, $val) = split(/:/,$av);-        $feat{$attr} = $val;-      }-      $feat{"__lemma__"} = $lemma;-      push @r_words, \%feat;-    }-    push @r_sentences, \@r_words;-  }-  return \@r_sentences-}--# ---------------------------------------------------------------------# morph-# ----------------------------------------------------------------------sub morph {-  my $lemma = shift;-  my $featsR = shift;-  my $cat = $featsR->{"cat"};-  return "$lemma:$cat";-}--# ---------------------------------------------------------------------# main-# ----------------------------------------------------------------------# slurp STDIN to $buf (copied from web)-my $holdTerminator = $/;-undef $/;-my $buf = <STDIN>;-$/ = $holdTerminator;--my @output = ();-my $reqsR = read_morph_request $buf;-foreach my $sentenceR (@$reqsR) {-  my @output_words = ();-  foreach my $wordR (@$sentenceR) {-    my $inflected = morph($wordR->{"__lemma__"}, $wordR);-    push @output_words, $inflected;-  }-  my $output_sentence = join(" ",@output_words);-  my @singleton = ( $output_sentence );-  push @output, \@singleton;-}--print to_json(\@output);
examples/artificial/lexicon view
@@ -46,7 +46,10 @@ tb-unification-noadj tb-unification-noadj () semantics:[tb-unification-noadj()] tb-unification-bot   tb-unification-bot () semantics:[tb-unification-bot()] tb-unification-adj   tb-unification-adj () semantics:[tb-unification-adj()]+tb-unification-na       tb-unification-na(?X)     semantics:[tb-unification-na(?X)]+tb-unification-anchor   tb-unification-anchor(?X) semantics:[tb-unification-anchor(?X)] + no-thing   no-thing   () semantics:[no-thing()] thing-good thing-good () semantics:[thing-good()] thing-bad  thing-bad  () semantics:[thing-bad()]@@ -54,3 +57,8 @@ "string-literal-in-lemma" term () semantics:["string-lit'+!|"(foo)]  lemanchor lemanchor() semantics:[lemanchor()]++preterminal preterminal() semantics:[preterminal()]++disjunction disjunction(x y z) semantics:[disjunction()]+variablecat variablecat(x y z) semantics:[variablecat()]
− examples/artificial/macros
@@ -1,126 +0,0 @@-% trivial example of the kid to parent rule-k2p-trivial() initial -Mother [cat:a]![] { Anchor anchor [ cat:x ]![] }--% note: the alphabetical names below are meaningless - they are just-% chinese numbers (which is why i follow them by the equivalent -% arabic numerals)-%-% why do i name them this way? dunno... figured they'd be easier-% to see or something---yi1() initial-YiMo [cat:a tb:?T]![tb:?B] {- YiLe anchor [ cat:x ]![]- YiRi type:subst  [ cat:b ]![]-}--er2() initial-Mother [cat:b]![] {-  Left anchor [ cat:x ]![]-  Right type:subst [ cat:t1 ]![]-}--term(?C ?X) initial-T anchor [cat:?C foo:?X]![]--aux-bad() auxiliary-Mother [cat:t1 tb:foo]![] {-  Left anchor [ cat:x ]![]-  Foot type:foot [cat:t1]![tb:bar]-}--aux-good() auxiliary-MothA [cat:t1 tb:ping]![] {-  LeftA anchor [cat:x]![]-  FootA type:foot [cat:t1]![tb:ping]-}--aux-nepas () auxiliary-Mother [cat:t1 tb:ping]![] {-  Left anchor [cat:x]![]-  Foot type:foot [cat:t1]![tb:ping]-  Right type:lex "pas"-}----% meant to receive substitution from san3 -% if it works - ?A should be set to bar-wu5 () initial-WuM [cat:a foo:?A]![] {-  WuL anchor [cat:x]![]-  WuR type:subst [cat:t1 foo:?A]![]-}--% a simple tb unification which ought to work-liu6-good () initial -Mother [cat:a]![cat:a] { Anchor anchor [cat:x]![] }--% unification + subst should work, but this should NOT propagate up! -% this should NOT propagate up-wu5-bad () initial-Mother [cat:a foo:?A]![] {-  Anch anchor [cat:x]![]-  Left  type:subst [cat:t1 foo:?A]![]-  Right type:subst [cat:t2 foo:?A]![]-}----% top-bot unification failure (simple)-liu6-bad1 () initial -Mother [cat:a]![cat:b] { Anch anchor [cat:x]![] }--% top-bot unification (complex)-liu6-bad2 () initial -Mother [cat:a tb:?X]![tb:?Y] {-  Anch anchor [cat:x]![]-  Left  type:subst [cat:t1 foo:?X]![]-  Right type:subst [cat:t2 foo:?Y]![]-}--% this should still be passed-iaf-killer-good (?X) initial-Mother [cat:a]![cat:a] {-  Anch anchor [cat:x]![]-  Left  type:subst [cat:t1 idx:?X]![]-  Right type:subst [cat:t2 idx:?X]![]-}--aconstr-with-anchor () initial-Anch anchor aconstr:noadj [cat:a]![]--% this succeeds iff thing is good or left unset-tb-unification-noadj () initial-M [cat:a]![] {-  X type:subst [cat:x thing:?X]![thing:good]-  Y anchor [cat:b]![]-}--tb-unification-bot() initial-M anchor [cat:a]![]--tb-unification-adj() auxiliary-M [cat:a]![idx:b] {- X anchor [cat:b]![]- Y type:foot [cat:a]![]-}--no-thing () initial-X anchor [cat:x]![]--thing-good () initial-X anchor [cat:x thing:good]![]--thing-bad () initial-X anchor [cat:x thing:bad]![]--lemanchor () initial-M [cat:x]![] {-  X anchor [cat:x]![]-  Y type:subst [cat:y]![lemanchor:hello]-  Z type:subst [cat:y]![lemanchor:world]-}-
examples/artificial/suite view
@@ -25,5 +25,10 @@ tb-noadj-good-2 semantics:[tb-unification-noadj() thing-good()] tb-unification-1 semantics:[tb-unification-bot()] tb-unification-2 semantics:[tb-unification-bot() tb-unification-adj()]+tb-unification-na-good semantics:[tb-unification-na(good)]+tb-unification-anchor-good semantics:[tb-unification-anchor(good)]  lemanchor semantics:[lemanchor()]+preterminal semantics:[preterminal()]+disjunction semantics:[disjunction()]+variablecat semantics:[variablecat()]
examples/artificial/suite-bad view
@@ -9,3 +9,5 @@ % aconstr:noadj nodes tb-noadj-bad semantics:[tb-unification-noadj() thing-bad()] +tb-unification-na-bad semantics:[tb-unification-na(bad)]+tb-unification-anchor-bad semantics:[tb-unification-anchor(bad)]
+ examples/artificial/trees view
@@ -0,0 +1,150 @@+% trivial example of the kid to parent rule+k2p-trivial() initial +Mother [cat:a]![] { Anchor anchor [ cat:x ]![] }++% note: the alphabetical names below are meaningless - they are just+% chinese numbers (which is why i follow them by the equivalent +% arabic numerals)+%+% why do i name them this way? dunno... figured they'd be easier+% to see or something+++yi1() initial+YiMo [cat:a tb:?T]![tb:?B] {+ YiLe anchor [ cat:x ]![]+ YiRi type:subst  [ cat:b ]![]+}++er2() initial+Mother [cat:b]![] {+  Left anchor [ cat:x ]![]+  Right type:subst [ cat:t1 ]![]+}++term(?C ?X) initial+T anchor [cat:?C foo:?X]![]++aux-bad() auxiliary+Mother [cat:t1 tb:foo]![] {+  Left anchor [ cat:x ]![]+  Foot type:foot [cat:t1]![tb:bar]+}++aux-good() auxiliary+MothA [cat:t1 tb:ping]![] {+  LeftA anchor [cat:x]![]+  FootA type:foot [cat:t1]![tb:ping]+}++aux-nepas () auxiliary+Mother [cat:t1 tb:ping]![] {+  Left anchor [cat:x]![]+  Foot type:foot [cat:t1]![tb:ping]+  Right type:lex "pas"+}++++% meant to receive substitution from san3 +% if it works - ?A should be set to bar+wu5 () initial+WuM [cat:a foo:?A]![] {+  WuL anchor [cat:x]![]+  WuR type:subst [cat:t1 foo:?A]![]+}++% a simple tb unification which ought to work+liu6-good () initial +Mother [cat:a]![cat:a] { Anchor anchor [cat:x]![] }++% unification + subst should work, but this should NOT propagate up! +% this should NOT propagate up+wu5-bad () initial+Mother [cat:a foo:?A]![] {+  Anch anchor [cat:x]![]+  Left  type:subst [cat:t1 foo:?A]![]+  Right type:subst [cat:t2 foo:?A]![]+}++++% top-bot unification failure (simple)+liu6-bad1 () initial +Mother [cat:a]![cat:b] { Anch anchor [cat:x]![] }++% top-bot unification (complex)+liu6-bad2 () initial +Mother [cat:a tb:?X]![tb:?Y] {+  Anch anchor [cat:x]![]+  Left  type:subst [cat:t1 foo:?X]![]+  Right type:subst [cat:t2 foo:?Y]![]+}++% this should still be passed+iaf-killer-good (?X) initial+Mother [cat:a]![cat:a] {+  Anch anchor [cat:x]![]+  Left  type:subst [cat:t1 idx:?X]![]+  Right type:subst [cat:t2 idx:?X]![]+}++aconstr-with-anchor () initial+Anch anchor aconstr:noadj [cat:a]![]++% this succeeds iff thing is good or left unset+tb-unification-noadj () initial+M [cat:a]![] {+  X type:subst [cat:x thing:?X]![thing:good]+  Y anchor [cat:b]![]+}++tb-unification-bot() initial+M anchor [cat:a]![]++tb-unification-adj() auxiliary+M [cat:a]![idx:b] {+ X anchor [cat:b]![]+ Y type:foot [cat:a]![]+}++tb-unification-na(?T) initial+X aconstr:noadj [cat:X thing:good]![thing:?T] {+ Y anchor [cat:X]![]+}++tb-unification-anchor(?T) initial+X [cat:X thing:good]![thing:?T] {+ Y anchor [cat:X thing:good]![thing:?T]+}+++no-thing () initial+X anchor [cat:x]![]++thing-good () initial+X anchor [cat:x thing:good]![]++thing-bad () initial+X anchor [cat:x thing:bad]![]++lemanchor () initial+M [cat:x]![] {+  X anchor [cat:x]![]+  Y type:subst [cat:y lemanchor:hello]![]+  Z type:subst [cat:y lemanchor:world]![]+}++preterminal () initial+M [cat:x]![] {+ X anchor [cat:x]![]+ Y [cat:y]![lemanchor:hello]+}+++disjunction(?X ?Y ?Z) initial+X anchor [cat:?X;?Y;?Z x:?X y:?Y z:?Z foo:?X/x|y|z;?Z;a]![]++variablecat(?X ?Y ?Z) initial+X anchor [cat:_ x:?X y:?Y z:?Z foo:?X/x|y|z;?Z;a]![]+
− examples/chatnoir/macros
@@ -1,132 +0,0 @@-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-%	DETERMINERS-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%--Det(?I) auxiliary-n1[cat:n idx:?I det:plus qu:minus]![cat:n idx:?I det:plus qu:minus]-{-  n2 anchor [cat:det]![]-  n4 type:foot [cat:n idx:?I det:?_ qu:?_]![cat:n idx:?I det:minus qu:?_]-}--%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-%	NOUNS-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%--% Common Nouns: voyage-nC(?I) initial-n1 anchor [cat:n idx:?I det:?_ qu:?_]![cat:n idx:?I det:minus qu:minus ]--% Proper Nouns: Jean-nP(?I) initial-n1 anchor [cat:n idx:?I det:plus qu:minus]![cat:n idx:?I det:plus qu:minus ]--%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-%	ADJECTIVES-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%--adj_post(?I)  auxiliary-n0[cat:n idx:?I det:?_ qu:?_]![cat:n idx:?I det:minus qu:minus ]-{-  n1 type:foot [cat:n idx:?I det:minus qu:minus]!-    [cat:n idx:?I det:minus qu:?_ ]-    n2 anchor [cat:a]![]-}--adj_pre(?I)  auxiliary-n0[cat:n idx:?I det:?_ qu:?_]![cat:n idx:?I det:minus qu:minus ]-{-  n1 anchor [cat:a]![]-  n3 type:foot [cat:n idx:?I det:minus qu:minus]!-    [cat:n idx:?I det:minus qu:?_ ]-}--%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-%	TRANSITIVE VERBS-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%--%infinitive- % chasser une souris vinfn1-vArity2:vinfn1(?E ?X ?Y)  initial-n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p idx:?E mode:?_ sujidx:?_]-{- n2 anchor [cat:v idx:?E]![]- n4 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:?_ qu:?_ ]-}--% declarative-  % le chat chasse la souris-vArity2:n0vn1(?E ?X ?Y) initial-n1[cat:p]![]-{-  n2 type:subst [cat:n idx:?X det:plus qu:minus]!-    [cat:n idx:?X det:?_ qu:?_ ]-    n3 anchor [cat:v idx:?E]![]-  n5 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y-    det:?_ qu:?_ ]-}--% question sujet	-  % qui chasse une souris ?-vArity2:qu0vn1(?E ?X ?Y) initial-n1[cat:p]![]-{-  n2 type:subst [cat:c idx:?X det:plus qu:minus]!-    [cat:c idx:?X det:?_ qu:?_ ]-    n3 anchor [cat:v idx:?E]![]-  n5 type:subst [cat:n idx:?Y det:plus qu:minus]!-    [cat:n idx:?Y det:?_ qu:?_ ]-}--% question objet-  % que chasse le chat ?-vArity2:qu1vn0(?E ?X ?Y) initial-n1[cat:p]![]-{-  n2 type:subst [cat:n idx:?Y det:plus qu:plus]!-    [cat:n idx:?Y det:?_ qu:plus ]-    n3[cat:p idx:?E]![]-    {-      % FIXME: EYK - the bottom node was cat:p, i set it to cat:v-      % to validate-      n4 anchor [cat:v idx:?E]![cat:v idx:?E]-      n6 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X-        det:?_ qu:?_ ]-    }-}--% relative sujet-% le chat qui chasse la souris--vArity2:rel0vn1(?E ?X ?Y) auxiliary-n0[cat:n idx:?X det:plus qu:?_]![cat:n idx:?X det:?_ qu:?_ ]-{-  n1 type:foot [cat:n idx:?X det:?_ qu:?_]![cat:n idx:?X det:?_ qu:?_ ]-    n2[cat:p]![]-    {-      n3 type:subst [cat:c idx:?X det:plus qu:minus]!-        [cat:c idx:?X det:?_ qu:?_ ]-        n4 anchor [cat:v idx:?E]![]-      n6 type:subst [cat:n idx:?Y det:plus qu:minus]!-        [cat:n idx:?Y det:?_ qu:?_ ]-    }}--% relative objet-% la souris que chasse le chat--vArity2:rel1vn0(?E ?X ?Y)  auxiliary-n0[cat:n idx:?Y det:plus qu:?_]![cat:n idx:?Y det:?_ qu:?_ ]-{-  n1 type:foot [cat:n idx:?Y det:?_ qu:?_]!-    [cat:n idx:?Y det:?_ qu:?_ ]-    n2[cat:p]![]-    {-      n3 type:subst [cat:c idx:?X det:plus qu:minus]!-        [cat:c idx:?X det:?_ qu:?_ ]-        n4 anchor [cat:v idx:?E]![]-      n6 type:subst [cat:n idx:?X det:plus qu:minus]!-        [cat:n idx:?X det:?_ qu:?_ ]         -    }-}--% vi: set cinoptions=0,p0:
+ examples/chatnoir/trees view
@@ -0,0 +1,132 @@+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%+%	DETERMINERS+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%++Det(?I) auxiliary+n1[cat:n idx:?I det:plus qu:minus]![cat:n idx:?I det:plus qu:minus]+{+  n2 anchor [cat:det]![]+  n4 type:foot [cat:n idx:?I det:?_ qu:?_]![cat:n idx:?I det:minus qu:?_]+}++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%+%	NOUNS+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%++% Common Nouns: voyage+nC(?I) initial+n1 anchor [cat:n idx:?I det:?_ qu:?_]![cat:n idx:?I det:minus qu:minus ]++% Proper Nouns: Jean+nP(?I) initial+n1 anchor [cat:n idx:?I det:plus qu:minus]![cat:n idx:?I det:plus qu:minus ]++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%+%	ADJECTIVES+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%++adj_post(?I)  auxiliary+n0[cat:n idx:?I det:?_ qu:?_]![cat:n idx:?I det:minus qu:minus ]+{+  n1 type:foot [cat:n idx:?I det:minus qu:minus]!+    [cat:n idx:?I det:minus qu:?_ ]+    n2 anchor [cat:a]![]+}++adj_pre(?I)  auxiliary+n0[cat:n idx:?I det:?_ qu:?_]![cat:n idx:?I det:minus qu:minus ]+{+  n1 anchor [cat:a]![]+  n3 type:foot [cat:n idx:?I det:minus qu:minus]!+    [cat:n idx:?I det:minus qu:?_ ]+}++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%+%	TRANSITIVE VERBS+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%++%infinitive+ % chasser une souris vinfn1+vArity2:vinfn1(?E ?X ?Y)  initial+n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p idx:?E mode:?_ sujidx:?_]+{+ n2 anchor [cat:v idx:?E]![]+ n4 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:?_ qu:?_ ]+}++% declarative+  % le chat chasse la souris+vArity2:n0vn1(?E ?X ?Y) initial+n1[cat:p]![]+{+  n2 type:subst [cat:n idx:?X det:plus qu:minus]!+    [cat:n idx:?X det:?_ qu:?_ ]+    n3 anchor [cat:v idx:?E]![]+  n5 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y+    det:?_ qu:?_ ]+}++% question sujet	+  % qui chasse une souris ?+vArity2:qu0vn1(?E ?X ?Y) initial+n1[cat:p]![]+{+  n2 type:subst [cat:c idx:?X det:plus qu:minus]!+    [cat:c idx:?X det:?_ qu:?_ ]+    n3 anchor [cat:v idx:?E]![]+  n5 type:subst [cat:n idx:?Y det:plus qu:minus]!+    [cat:n idx:?Y det:?_ qu:?_ ]+}++% question objet+  % que chasse le chat ?+vArity2:qu1vn0(?E ?X ?Y) initial+n1[cat:p]![]+{+  n2 type:subst [cat:n idx:?Y det:plus qu:plus]!+    [cat:n idx:?Y det:?_ qu:plus ]+    n3[cat:p idx:?E]![]+    {+      % FIXME: EYK - the bottom node was cat:p, i set it to cat:v+      % to validate+      n4 anchor [cat:v idx:?E]![cat:v idx:?E]+      n6 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X+        det:?_ qu:?_ ]+    }+}++% relative sujet+% le chat qui chasse la souris++vArity2:rel0vn1(?E ?X ?Y) auxiliary+n0[cat:n idx:?X det:plus qu:?_]![cat:n idx:?X det:?_ qu:?_ ]+{+  n1 type:foot [cat:n idx:?X det:?_ qu:?_]![cat:n idx:?X det:?_ qu:?_ ]+    n2[cat:p]![]+    {+      n3 type:subst [cat:c idx:?X det:plus qu:minus]!+        [cat:c idx:?X det:?_ qu:?_ ]+        n4 anchor [cat:v idx:?E]![]+      n6 type:subst [cat:n idx:?Y det:plus qu:minus]!+        [cat:n idx:?Y det:?_ qu:?_ ]+    }}++% relative objet+% la souris que chasse le chat++vArity2:rel1vn0(?E ?X ?Y)  auxiliary+n0[cat:n idx:?Y det:plus qu:?_]![cat:n idx:?Y det:?_ qu:?_ ]+{+  n1 type:foot [cat:n idx:?Y det:?_ qu:?_]!+    [cat:n idx:?Y det:?_ qu:?_ ]+    n2[cat:p]![]+    {+      n3 type:subst [cat:c idx:?X det:plus qu:minus]!+        [cat:c idx:?X det:?_ qu:?_ ]+        n4 anchor [cat:v idx:?E]![]+      n6 type:subst [cat:n idx:?X det:plus qu:minus]!+        [cat:n idx:?X det:?_ qu:?_ ]         +    }+}++% vi: set cinoptions=0,p0:
− examples/demo/macros
@@ -1,439 +0,0 @@-%% 02 april 2004-%% 1. Jean promet un cadeau a Marie-%% 2. Jean promet a Marie de partir-%% 3. Qui promet un cadeau a Marie?-%% 4. Que promet Jean a Marie?-%% 5. A qui Jean promet-il un cadeau?-%% 6. la personne qui promet un cadeau a Marie-%% 7. le cadeau que Jean promet a Marie-%% 8. la personne a qui Jean promet un cadeau-%% 9. promettre un cadeau a Marie-%% 10. promettant un cadeau a Marie-%% 11. donner un livre a marie--Det(?I) auxiliary-n1[cat:n idx:?I det:_ qu:minus]![cat:n idx:?I det:_ qu:minus]-{-  n2 anchor [cat:det]![]-  n4 type:foot [cat:n idx:?I det:_ qu:_ ]![cat:n idx:?I det:minus qu:_ ]-}--  % Common Nouns: voyage-nC(?I) initial-  n1 anchor [cat:n idx:?I det:_ qu:?W ]![cat:n idx:?I det:minus qu:minus ]-% Proper Nouns: Jean--nP(?I) initial-  n1 anchor [cat:n idx:?I det:plus qu:minus]![cat:n idx:?I det:plus qu:minus ]--  %1 declarative	gn promet gn sp_a-n0vn1sp2(?E ?X ?Y ?Z) initial-  n1[cat:p]![]-{-  n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]-    n3 anchor [cat:v idx:?E]![]-  n5 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_ ]-    n6[cat:sp idx:?Z det:plus]![det:_ ]-    { n8[cat:prep]![]-      {-        n9 type:lex "a"-      }-      n10 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z-        det:_ qu:_] -    }-}--  %2 infinitive	V GN SP_a-vinfn1sp2(?E ?X ?Y ?Z)  initial-  n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p idx:?E mode:_ sujidx:_]-{-  n2 anchor [cat:v idx:?E]![]-  n4 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_ ]-    n5[cat:sp idx:?Z det:plus]![det:_ ]-    { n6[cat:prep]![]-      {-        n7 type:lex "a"-      }-      n8 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z-        det:_ qu:_] -    }-}--  %3 question sujet	qui V GN GP_a ?-qu0vn1sp2(?E ?X ?Y ?Z) initial-  n1[cat:p]![]-{-  n2 type:subst [cat:c idx:?X det:plus qu:minus]![idx:?X det:_ qu:_ ]-    n3 anchor [cat:v idx:?E]![]-  n5 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_ ]-    n6[cat:sp idx:?Z det:plus]![det:_ ]-    { n8[cat:prep]![]-      {-        n9 type:lex "a"-      }-      n10 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z det:_ qu:_ ] -    }-}--  %4 question objet-qu1vn0sp2(?E ?X ?Y ?Z) initial-  n1[cat:p]![]-{-  n2 type:subst [cat:n idx:?Y det:plus qu:plus]![cat:n idx:?Y det:_ qu:plus ]-    n3[cat:p idx:?E]![]-    {-      n4 anchor [cat:v idx:?E]![idx:?E]-      n6 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X-        det:_ qu:_ ]-        n7[cat:sp idx:?Z det:plus]![det:_ ]-        { n8[cat:prep]![]-          {-            n9 type:lex "a"-          }-          n10 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z	det:_ qu:_] -        }-    }-}--  %5 question objet indirect-qu2n0vn1(?E ?X ?Y ?Z) initial-  n1[cat:p]![]-{-  n2[cat:sp idx:?Z det:plus]![det:_ ]-  { n3[cat:prep]![]-    {-      n4 type:lex "a"-    }-    n5 type:subst [cat:n idx:?Z det:plus qu:plus]![cat:n idx:?Z det:_ qu:plus] -  }-  n6[cat:p idx:?E]![]-  {-    n7 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:minus ]-      n8 anchor [cat:v idx:?E]![idx:?E]-    n10 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_ ]-  }-}--%6 relative sujet	qui V gn sp_a -rel0vn1sp2(?E ?X ?Y ?Z) auxiliary-n0[cat:n idx:?X det:plus qu:_]![cat:n idx:?X det:_ qu:_ ]-{-  n1 type:foot [cat:n idx:?X det:_ qu:_]![cat:n idx:?X det:_ qu:_ ]-    n2[cat:p]![]-    {-      n3 type:subst [cat:c idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]-        n4 anchor [cat:v idx:?E]![]-      n6 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_ ]-        n7[cat:sp idx:?Z ]![]-        { n8[cat:prep]![]-          {-            n9 type:lex "a"-          }-          n10 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:_-            det:_ qu:_] -        }-      n9[cat:p]![]-      {n10[cat:prep]![]-        {-          n11 type:lex "de"-        } -        n12 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z -          mode:_ sujidx:_]-      }}}--%7 relative objet-rel1vn0sp2(?E ?X ?Y ?Z) auxiliary-n0[cat:n idx:?Y det:plus qu:_]![cat:n idx:?Y det:_ qu:_ ]-{-  n1 type:foot [cat:n idx:?Y det:_ qu:_]![cat:n idx:?Y det:_ qu:_ ]-    n2[cat:p]![]-    {-      n3 type:subst [cat:c idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]-        n4 anchor [cat:v idx:?E]![]-      n6 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]-        n7[cat:sp idx:?Z ]![]-        { n8[cat:prep]![]-          {-            n9 type:lex "a"-          }-          n10 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:_-            det:_ qu:_] -        }-    }-}--%8 relative objet indirect-rel2n0vn1(?E ?X ?Y ?Z) auxiliary-n0[cat:n idx:?Z det:plus qu:_]![cat:n idx:?Z det:_ qu:_ ]-{-  n1 type:foot [cat:n idx:?Z det:_ qu:_]![cat:n idx:?Z det:_ qu:_]-    n2[cat:p]![]-    {-      n3[cat:sp idx:?Z det:plus]![det:_ ]-      { n4[cat:prep]![]-        {-          n5 type:lex "a"-        }-        n6 type:subst [cat:n idx:?Z det:plus qu:plus]![cat:n idx:?Z det:_ qu:plus] -      }-      n7[cat:p idx:?E]![]-      {-        n8 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:minus ]-          n9 anchor [cat:v idx:?E]![cat:p idx:?E]-        n11 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_ ]-      }-    }-}--  %9 declarative	GN V GN_a Pinf_de-n0vsp2pinf1(?E ?X ?Y ?Z) initial-  n1[cat:p]![]-{-  n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]-    n3 anchor [cat:v idx:?E]![]-  n5[cat:sp idx:?Y det:plus]![det:_ ]-  { n6[cat:prep]![]-    {-      n7 type:lex "a"-    }-    n8 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_] -  }-  n9[cat:p]![]-  {n10[cat:prep]![]-    {-      n11 type:lex "de"-    } -    n12 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![idx:?Z mode:_ sujidx:_]-  }-}--  %10 infinitive	V SP_a Inf_de-vinfsp2pinf1(?E ?X ?Y ?Z) initial-  n1[cat:p idx:?E mode:inf sujidx:?X]![idx:?Y mode:_ sujidx:_]-{-  n2 anchor [cat:v idx:?E]![]-  n4[cat:sp idx:?Z det:plus]![det:_ ]-  { n5[cat:prep]![]-    {-      n6 type:lex "a"-    }-    n7 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z-      det:_ qu:_] -  }-  n8[cat:p]![]-  {n9[cat:prep]![]-    {-      n10 type:lex "de"-    } -    n11 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z -      mode:_ sujidx:_]-  }-}--  %11 question sujet	qui V GP_a Pinf_de ?-qu0vsp2pinf1(?E ?X ?Y ?Z) initial -  n1[cat:p]![]-{-  n2 type:subst [cat:c idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]-    n3 anchor [cat:v idx:?E]![]-  n5[cat:sp idx:?Z det:plus]![det:_ ]-  { n6[cat:prep]![]-    {-      n7 type:lex "a"-    }-    n8 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z det:_ qu:_ ] -  }-  n9[cat:p]![]-  {n10[cat:prep]![]-    {-      n11 type:lex "de"-    } -    n12 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z -      mode:_ sujidx:_]-  }}--  %12 question objet indirect-qu2n0vpinf1(?E ?X ?Y ?Z) initial-  n1[cat:p]![]-{-  n2[cat:sp idx:?Z det:plus]![det:_ ]-  { n3[cat:prep]![]-    {-      n4 type:lex "a"-    }-    n5 type:subst [cat:n idx:?Z det:plus qu:plus]![cat:n idx:?Z det:_ qu:plus] -  }-  n6[cat:p idx:?E]![]-  {-    n7 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:minus ]-      n8 anchor [cat:v idx:?E]![cat:p idx:?E]-  }-  n10[cat:prep]![]-  {-    n11 type:lex "de"-  } -  n12 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z -    mode:_ sujidx:_]-}--%13 relative sujet	qui V sp_a pinf_de-rel0vsp2pinf1(?E ?X ?Y ?Z) auxiliary-n0[cat:n idx:?X det:plus qu:_]![cat:n idx:?X det:_ qu:_ ]-{-  n1 type:foot [cat:n idx:?X det:_ qu:_]![cat:n idx:?X det:_ qu:_ ]-    n2[cat:p]![]-    {-      n3 type:subst [cat:c idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]-        n4 anchor [cat:v idx:?E]![]-      n6[cat:sp idx:?Z ]![]-      { n7[cat:prep]![]-        {-          n8 type:lex "a"-        }-        n9 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:_-          det:_ qu:_] -      }-      n10[cat:p]![]-      {n11[cat:prep]![]-        {-          n12 type:lex "de"-        } -        n13 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z -          mode:_ sujidx:_]-      }}}--%14 relative objet indirect	a qui GN v Pinf_de-rel2n0vpinf1(?E ?X ?Y ?Z) auxiliary-n0[cat:n idx:?Z det:plus qu:_]![cat:n idx:?Z det:_ qu:_ ]-{-  n1 type:foot [cat:n idx:?Z det:_ qu:_]![cat:n idx:?Z det:_ qu:_]-    n2[cat:p]![]-    {-      n3[cat:sp idx:?Z det:plus]![det:_ ]-      { n4[cat:prep]![]-        {-          n5 type:lex "a"-        }-        n6 type:subst [cat:n idx:?Z det:plus qu:plus]![cat:n idx:?Z det:_ qu:plus] -      }-      n7[cat:p idx:?E]![]-      {-        n8 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:minus ]-          n9 anchor [cat:v idx:?E]![cat:p idx:?E]-      }-      n9[cat:p]![]-      {n10[cat:prep]![]-        {-          n11 type:lex "de"-        } -        n12 type:subst [cat:p idx:?Y mode:inf sujidx:?X]![cat:p idx:?Y-          mode:_ sujidx:_]-      }-    }}---  %15 declarative gn0 persuade gn2 pinf_de1	n0vn2pinf1 -n0vn2pinf1(?E ?X ?Y ?Z) initial-  n1[cat:p]![]-{-  n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]-    n3 anchor [cat:v idx:?E]![]-  n5 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_]-    n6[cat:p]![]-    {n7[cat:prep]![]-      {-        n8 type:lex "de"-      } -      n9 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![idx:?Z mode:_ sujidx:_]-    }-}--  %15 infinitive persuader gn  pinf_de	vinfn2pinf1-vinfn2pinf1(?E ?X ?Y ?Z) initial-  n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p idx:?Y mode:_ sujidx:_]-{-  n2 anchor [cat:v idx:?E]![]-  n4 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y-    det:_ qu:_] -    n5[cat:p]![]-    {n6[cat:prep]![]-      {-        n7 type:lex "de"-      } -      n8 type:subst [cat:p idx:?Z mode:inf sujidx:?Y]![cat:p idx:?Z -        mode:_ sujidx:_]-    }-}--  %16 qu-sujet qui persuade gn  pinf_de ?	qu0vn2pinf1-qu0vn2pinf1(?E ?X ?Y ?Z) initial-  n1[cat:p]![]-{-  n2 type:subst [cat:c idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]-    n3 anchor [cat:v idx:?E]![]-  n5 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z det:_ qu:_ ] -    n6[cat:p]![]-    {n7[cat:prep]![]-      {-        n8 type:lex "de"-      } -      n9 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z -        mode:_ sujidx:_]-    }}--  %17 qu-obj	 qui gn persuade-il pinf_de ?	qu2n0vpinf1-qu2n0vpinf1(?E ?X ?Y ?Z) initial-  n1[cat:p]![]-{-  n2 type:subst [cat:n idx:?Z det:plus qu:plus]![cat:n idx:?Z det:_ qu:plus] -    n3[cat:p idx:?E]![]-    {-      n4 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:minus ]-        n5 anchor [cat:v idx:?E]![cat:p idx:?E]-    }-  n7[cat:prep]![]-  {-    n8 type:lex "de"-  } -  n9 type:subst [cat:p idx:?Y mode:inf sujidx:?X]![cat:p idx:?Y -    mode:_ sujidx:_]-}--%18 rel-sjt	 n qui persuade gn  pinf_de	rel0vn2pinf1-rel0vn2pinf1(?E ?X ?Y ?Z) auxiliary-n0[cat:n idx:?X det:plus qu:_]![cat:n idx:?X det:_ qu:_ ]-{-  n1 type:foot [cat:n idx:?X det:_ qu:_]![cat:n idx:?X det:_ qu:_ ]-    n2[cat:p]![]-    {-      n3 type:subst [cat:c idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]-        n4 anchor [cat:v idx:?E]![]-      n6 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:_-        det:_ qu:_] -        n7[cat:p]![]-        {n8[cat:prep]![]-          {-            n9 type:lex "de"-          } -          n10 type:subst [cat:p idx:?Y mode:inf sujidx:?X]![cat:p idx:?Y -            mode:_ sujidx:_]-        }}}--%19 rel-obj	  n dont gn persuade gn		rel1n0vn2-rel1n0vn2(?E ?X ?Y ?Z) auxiliary-n0[cat:n idx:?Y det:plus qu:_]![cat:n idx:?Y det:_ qu:_ ]-{-  n1 type:foot [cat:n idx:?Y det:_ qu:_]![cat:n idx:?Y det:_ qu:_]-    n2[cat:p]![]-    {-      n3 type:subst [cat:c idx:?Y det:plus qu:_]![cat:c idx:?Y det:_ qu:_] -        n4[cat:p idx:?E]![]-        {-          n5 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:minus ]-            n6 anchor [cat:v idx:?E]![cat:p idx:?E]-        }-      n8 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y -        det:_ qu:minus ]-    }-}-
+ examples/demo/trees view
@@ -0,0 +1,439 @@+%% 02 april 2004+%% 1. Jean promet un cadeau a Marie+%% 2. Jean promet a Marie de partir+%% 3. Qui promet un cadeau a Marie?+%% 4. Que promet Jean a Marie?+%% 5. A qui Jean promet-il un cadeau?+%% 6. la personne qui promet un cadeau a Marie+%% 7. le cadeau que Jean promet a Marie+%% 8. la personne a qui Jean promet un cadeau+%% 9. promettre un cadeau a Marie+%% 10. promettant un cadeau a Marie+%% 11. donner un livre a marie++Det(?I) auxiliary+n1[cat:n idx:?I det:_ qu:minus]![cat:n idx:?I det:_ qu:minus]+{+  n2 anchor [cat:det]![]+  n4 type:foot [cat:n idx:?I det:_ qu:_ ]![cat:n idx:?I det:minus qu:_ ]+}++  % Common Nouns: voyage+nC(?I) initial+  n1 anchor [cat:n idx:?I det:_ qu:?W ]![cat:n idx:?I det:minus qu:minus ]+% Proper Nouns: Jean++nP(?I) initial+  n1 anchor [cat:n idx:?I det:plus qu:minus]![cat:n idx:?I det:plus qu:minus ]++  %1 declarative	gn promet gn sp_a+n0vn1sp2(?E ?X ?Y ?Z) initial+  n1[cat:p]![]+{+  n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]+    n3 anchor [cat:v idx:?E]![]+  n5 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_ ]+    n6[cat:sp idx:?Z det:plus]![det:_ ]+    { n8[cat:prep]![]+      {+        n9 type:lex "a"+      }+      n10 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z+        det:_ qu:_] +    }+}++  %2 infinitive	V GN SP_a+vinfn1sp2(?E ?X ?Y ?Z)  initial+  n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p idx:?E mode:_ sujidx:_]+{+  n2 anchor [cat:v idx:?E]![]+  n4 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_ ]+    n5[cat:sp idx:?Z det:plus]![det:_ ]+    { n6[cat:prep]![]+      {+        n7 type:lex "a"+      }+      n8 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z+        det:_ qu:_] +    }+}++  %3 question sujet	qui V GN GP_a ?+qu0vn1sp2(?E ?X ?Y ?Z) initial+  n1[cat:p]![]+{+  n2 type:subst [cat:c idx:?X det:plus qu:minus]![idx:?X det:_ qu:_ ]+    n3 anchor [cat:v idx:?E]![]+  n5 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_ ]+    n6[cat:sp idx:?Z det:plus]![det:_ ]+    { n8[cat:prep]![]+      {+        n9 type:lex "a"+      }+      n10 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z det:_ qu:_ ] +    }+}++  %4 question objet+qu1vn0sp2(?E ?X ?Y ?Z) initial+  n1[cat:p]![]+{+  n2 type:subst [cat:n idx:?Y det:plus qu:plus]![cat:n idx:?Y det:_ qu:plus ]+    n3[cat:p idx:?E]![]+    {+      n4 anchor [cat:v idx:?E]![idx:?E]+      n6 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X+        det:_ qu:_ ]+        n7[cat:sp idx:?Z det:plus]![det:_ ]+        { n8[cat:prep]![]+          {+            n9 type:lex "a"+          }+          n10 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z	det:_ qu:_] +        }+    }+}++  %5 question objet indirect+qu2n0vn1(?E ?X ?Y ?Z) initial+  n1[cat:p]![]+{+  n2[cat:sp idx:?Z det:plus]![det:_ ]+  { n3[cat:prep]![]+    {+      n4 type:lex "a"+    }+    n5 type:subst [cat:n idx:?Z det:plus qu:plus]![cat:n idx:?Z det:_ qu:plus] +  }+  n6[cat:p idx:?E]![]+  {+    n7 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:minus ]+      n8 anchor [cat:v idx:?E]![idx:?E]+    n10 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_ ]+  }+}++%6 relative sujet	qui V gn sp_a +rel0vn1sp2(?E ?X ?Y ?Z) auxiliary+n0[cat:n idx:?X det:plus qu:_]![cat:n idx:?X det:_ qu:_ ]+{+  n1 type:foot [cat:n idx:?X det:_ qu:_]![cat:n idx:?X det:_ qu:_ ]+    n2[cat:p]![]+    {+      n3 type:subst [cat:c idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]+        n4 anchor [cat:v idx:?E]![]+      n6 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_ ]+        n7[cat:sp idx:?Z ]![]+        { n8[cat:prep]![]+          {+            n9 type:lex "a"+          }+          n10 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:_+            det:_ qu:_] +        }+      n9[cat:p]![]+      {n10[cat:prep]![]+        {+          n11 type:lex "de"+        } +        n12 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z +          mode:_ sujidx:_]+      }}}++%7 relative objet+rel1vn0sp2(?E ?X ?Y ?Z) auxiliary+n0[cat:n idx:?Y det:plus qu:_]![cat:n idx:?Y det:_ qu:_ ]+{+  n1 type:foot [cat:n idx:?Y det:_ qu:_]![cat:n idx:?Y det:_ qu:_ ]+    n2[cat:p]![]+    {+      n3 type:subst [cat:c idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]+        n4 anchor [cat:v idx:?E]![]+      n6 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]+        n7[cat:sp idx:?Z ]![]+        { n8[cat:prep]![]+          {+            n9 type:lex "a"+          }+          n10 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:_+            det:_ qu:_] +        }+    }+}++%8 relative objet indirect+rel2n0vn1(?E ?X ?Y ?Z) auxiliary+n0[cat:n idx:?Z det:plus qu:_]![cat:n idx:?Z det:_ qu:_ ]+{+  n1 type:foot [cat:n idx:?Z det:_ qu:_]![cat:n idx:?Z det:_ qu:_]+    n2[cat:p]![]+    {+      n3[cat:sp idx:?Z det:plus]![det:_ ]+      { n4[cat:prep]![]+        {+          n5 type:lex "a"+        }+        n6 type:subst [cat:n idx:?Z det:plus qu:plus]![cat:n idx:?Z det:_ qu:plus] +      }+      n7[cat:p idx:?E]![]+      {+        n8 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:minus ]+          n9 anchor [cat:v idx:?E]![cat:p idx:?E]+        n11 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_ ]+      }+    }+}++  %9 declarative	GN V GN_a Pinf_de+n0vsp2pinf1(?E ?X ?Y ?Z) initial+  n1[cat:p]![]+{+  n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]+    n3 anchor [cat:v idx:?E]![]+  n5[cat:sp idx:?Y det:plus]![det:_ ]+  { n6[cat:prep]![]+    {+      n7 type:lex "a"+    }+    n8 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_] +  }+  n9[cat:p]![]+  {n10[cat:prep]![]+    {+      n11 type:lex "de"+    } +    n12 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![idx:?Z mode:_ sujidx:_]+  }+}++  %10 infinitive	V SP_a Inf_de+vinfsp2pinf1(?E ?X ?Y ?Z) initial+  n1[cat:p idx:?E mode:inf sujidx:?X]![idx:?Y mode:_ sujidx:_]+{+  n2 anchor [cat:v idx:?E]![]+  n4[cat:sp idx:?Z det:plus]![det:_ ]+  { n5[cat:prep]![]+    {+      n6 type:lex "a"+    }+    n7 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z+      det:_ qu:_] +  }+  n8[cat:p]![]+  {n9[cat:prep]![]+    {+      n10 type:lex "de"+    } +    n11 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z +      mode:_ sujidx:_]+  }+}++  %11 question sujet	qui V GP_a Pinf_de ?+qu0vsp2pinf1(?E ?X ?Y ?Z) initial +  n1[cat:p]![]+{+  n2 type:subst [cat:c idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]+    n3 anchor [cat:v idx:?E]![]+  n5[cat:sp idx:?Z det:plus]![det:_ ]+  { n6[cat:prep]![]+    {+      n7 type:lex "a"+    }+    n8 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z det:_ qu:_ ] +  }+  n9[cat:p]![]+  {n10[cat:prep]![]+    {+      n11 type:lex "de"+    } +    n12 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z +      mode:_ sujidx:_]+  }}++  %12 question objet indirect+qu2n0vpinf1(?E ?X ?Y ?Z) initial+  n1[cat:p]![]+{+  n2[cat:sp idx:?Z det:plus]![det:_ ]+  { n3[cat:prep]![]+    {+      n4 type:lex "a"+    }+    n5 type:subst [cat:n idx:?Z det:plus qu:plus]![cat:n idx:?Z det:_ qu:plus] +  }+  n6[cat:p idx:?E]![]+  {+    n7 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:minus ]+      n8 anchor [cat:v idx:?E]![cat:p idx:?E]+  }+  n10[cat:prep]![]+  {+    n11 type:lex "de"+  } +  n12 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z +    mode:_ sujidx:_]+}++%13 relative sujet	qui V sp_a pinf_de+rel0vsp2pinf1(?E ?X ?Y ?Z) auxiliary+n0[cat:n idx:?X det:plus qu:_]![cat:n idx:?X det:_ qu:_ ]+{+  n1 type:foot [cat:n idx:?X det:_ qu:_]![cat:n idx:?X det:_ qu:_ ]+    n2[cat:p]![]+    {+      n3 type:subst [cat:c idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]+        n4 anchor [cat:v idx:?E]![]+      n6[cat:sp idx:?Z ]![]+      { n7[cat:prep]![]+        {+          n8 type:lex "a"+        }+        n9 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:_+          det:_ qu:_] +      }+      n10[cat:p]![]+      {n11[cat:prep]![]+        {+          n12 type:lex "de"+        } +        n13 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z +          mode:_ sujidx:_]+      }}}++%14 relative objet indirect	a qui GN v Pinf_de+rel2n0vpinf1(?E ?X ?Y ?Z) auxiliary+n0[cat:n idx:?Z det:plus qu:_]![cat:n idx:?Z det:_ qu:_ ]+{+  n1 type:foot [cat:n idx:?Z det:_ qu:_]![cat:n idx:?Z det:_ qu:_]+    n2[cat:p]![]+    {+      n3[cat:sp idx:?Z det:plus]![det:_ ]+      { n4[cat:prep]![]+        {+          n5 type:lex "a"+        }+        n6 type:subst [cat:n idx:?Z det:plus qu:plus]![cat:n idx:?Z det:_ qu:plus] +      }+      n7[cat:p idx:?E]![]+      {+        n8 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:minus ]+          n9 anchor [cat:v idx:?E]![cat:p idx:?E]+      }+      n9[cat:p]![]+      {n10[cat:prep]![]+        {+          n11 type:lex "de"+        } +        n12 type:subst [cat:p idx:?Y mode:inf sujidx:?X]![cat:p idx:?Y+          mode:_ sujidx:_]+      }+    }}+++  %15 declarative gn0 persuade gn2 pinf_de1	n0vn2pinf1 +n0vn2pinf1(?E ?X ?Y ?Z) initial+  n1[cat:p]![]+{+  n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]+    n3 anchor [cat:v idx:?E]![]+  n5 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_]+    n6[cat:p]![]+    {n7[cat:prep]![]+      {+        n8 type:lex "de"+      } +      n9 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![idx:?Z mode:_ sujidx:_]+    }+}++  %15 infinitive persuader gn  pinf_de	vinfn2pinf1+vinfn2pinf1(?E ?X ?Y ?Z) initial+  n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p idx:?Y mode:_ sujidx:_]+{+  n2 anchor [cat:v idx:?E]![]+  n4 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y+    det:_ qu:_] +    n5[cat:p]![]+    {n6[cat:prep]![]+      {+        n7 type:lex "de"+      } +      n8 type:subst [cat:p idx:?Z mode:inf sujidx:?Y]![cat:p idx:?Z +        mode:_ sujidx:_]+    }+}++  %16 qu-sujet qui persuade gn  pinf_de ?	qu0vn2pinf1+qu0vn2pinf1(?E ?X ?Y ?Z) initial+  n1[cat:p]![]+{+  n2 type:subst [cat:c idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]+    n3 anchor [cat:v idx:?E]![]+  n5 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z det:_ qu:_ ] +    n6[cat:p]![]+    {n7[cat:prep]![]+      {+        n8 type:lex "de"+      } +      n9 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z +        mode:_ sujidx:_]+    }}++  %17 qu-obj	 qui gn persuade-il pinf_de ?	qu2n0vpinf1+qu2n0vpinf1(?E ?X ?Y ?Z) initial+  n1[cat:p]![]+{+  n2 type:subst [cat:n idx:?Z det:plus qu:plus]![cat:n idx:?Z det:_ qu:plus] +    n3[cat:p idx:?E]![]+    {+      n4 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:minus ]+        n5 anchor [cat:v idx:?E]![cat:p idx:?E]+    }+  n7[cat:prep]![]+  {+    n8 type:lex "de"+  } +  n9 type:subst [cat:p idx:?Y mode:inf sujidx:?X]![cat:p idx:?Y +    mode:_ sujidx:_]+}++%18 rel-sjt	 n qui persuade gn  pinf_de	rel0vn2pinf1+rel0vn2pinf1(?E ?X ?Y ?Z) auxiliary+n0[cat:n idx:?X det:plus qu:_]![cat:n idx:?X det:_ qu:_ ]+{+  n1 type:foot [cat:n idx:?X det:_ qu:_]![cat:n idx:?X det:_ qu:_ ]+    n2[cat:p]![]+    {+      n3 type:subst [cat:c idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]+        n4 anchor [cat:v idx:?E]![]+      n6 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:_+        det:_ qu:_] +        n7[cat:p]![]+        {n8[cat:prep]![]+          {+            n9 type:lex "de"+          } +          n10 type:subst [cat:p idx:?Y mode:inf sujidx:?X]![cat:p idx:?Y +            mode:_ sujidx:_]+        }}}++%19 rel-obj	  n dont gn persuade gn		rel1n0vn2+rel1n0vn2(?E ?X ?Y ?Z) auxiliary+n0[cat:n idx:?Y det:plus qu:_]![cat:n idx:?Y det:_ qu:_ ]+{+  n1 type:foot [cat:n idx:?Y det:_ qu:_]![cat:n idx:?Y det:_ qu:_]+    n2[cat:p]![]+    {+      n3 type:subst [cat:c idx:?Y det:plus qu:_]![cat:c idx:?Y det:_ qu:_] +        n4[cat:p idx:?E]![]+        {+          n5 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:minus ]+            n6 anchor [cat:v idx:?E]![cat:p idx:?E]+        }+      n8 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y +        det:_ qu:minus ]+    }+}+
examples/ej/lexicon view
@@ -48,9 +48,13 @@ Vinny Pn(?Entity ! agr:sg3) semantics:[name(_ ?Entity vincent)] +% Unicode Émilie Pn(?Entity ! agr:sg3) semantics:[name(_ ?Entity émilie)] +% string literals+"Joe \"the Boxer\" Stephens" Pn(?Entity ! agr:sg3)+semantics:[name(_ ?Entity joe_stephens)]  %% Verbs %% intransitive verbs
− examples/ej/macros
@@ -1,92 +0,0 @@-%% -%% Tree Templates-%%-%%-%% INITIAL TREES-%%   s trees-%%     (IntrV, TrV, TrVPP)-%%   np trees-%%     (Dp, Pn)-%%   n trees-%%     (Cn)-%%-%% AUXILIARY TREES-%%   n trees-%%     (Adj)-%%   vp trees-%%     (Adv)---%% INITIAL TREES--vArity1:IntrV(?Event ?Agent ! agr:?A) initial-	n1[cat:s idx:?Event]![]-	{	-	 n2 type:subst [cat:np idx:?Agent]![]-	 n3 [cat:vp idx:?Event]![]-	  {-	   n4 anchor [cat:v idx:?Event]![]-	  }-	}--vArity2:TrV(?Event ?Agent ?Experiencer ! agr:?A) initial-	n1[cat:s idx:?Event]![]-	{-	 n2 type:subst [cat:np idx:?Agent ]![]-	 n3[cat:vp idx:?Event]![]-	  {-	   n4 anchor [cat:v idx:?Event]![]-	   n6 type:subst [cat:np idx:?Experiencer ]![]-	  }-	}--vArity3:TrVPP(?Event ?Agent ?Theme ?Loc ! agr:?A) initial-	n1[cat:s idx:?Event]![]-	{-	  n2 type:subst [cat:np idx:?Agent ]![]-	  n3[cat:vp idx:?Event]![]-	  {-	    n4 anchor [cat:v idx:?Event]![]-	    n6 type:subst [cat:np idx:?Theme ]![]-	    n7 aconstr:noadj [cat:pp]![]-            {-	      n8[cat:p]![]-	      {-	        n9 type:lex "from"-	      }-	      n10 type:subst [cat:np idx:?Loc ]![]-	    }-	  }-	}--Dp(?Entity ! agr:?A) initial-	n1[cat:np idx:?Entity]![]-	{-	  n2 anchor [cat:det]![]-	  n4 type:subst [cat:n idx:?Entity ]![]-	}--Pn(?Entity ! agr:?A) initial-	n1[cat:np idx:?Entity]![]-	{-	 n2 anchor [cat:pn idx:?Entity]![]-	}--Cn(?Entity ! agr:?A) initial-	n1 anchor [cat:n idx:?Entity]![]--%% ?AUXILIARY ?TREES--Adj(?Entity) auxiliary-	n1[cat:n idx:?Entity]![]-	{-	  n2 anchor [cat:adj]![]-	  n4 type:foot [cat:n idx:?Entity ]![]-	}--Adv(?Event) auxiliary-	n1[cat:vp idx:?Event]![]-	{-	  n2 type:foot [cat:vp idx:?Event]![]-	  n3 anchor [cat:adv]![]-	}	
examples/ej/suite view
@@ -18,6 +18,12 @@              name(s2 ex émilie)] [Vincent loves Émilie] +v_loves_j+semantics: [ name(s1 a vincent)+             love(e a ex)+             name(s2 ex joe_stephens)]+[Vincent loves Joe "the Boxer" Stephens]+ v_loves_m_f semantics : [name(s1 a vincent)              love(e a ex)
+ examples/ej/trees view
@@ -0,0 +1,92 @@+%% +%% Tree Templates+%%+%%+%% INITIAL TREES+%%   s trees+%%     (IntrV, TrV, TrVPP)+%%   np trees+%%     (Dp, Pn)+%%   n trees+%%     (Cn)+%%+%% AUXILIARY TREES+%%   n trees+%%     (Adj)+%%   vp trees+%%     (Adv)+++%% INITIAL TREES++vArity1:IntrV(?Event ?Agent ! agr:?A) initial+	n1[cat:s idx:?Event]![]+	{	+	 n2 type:subst [cat:np idx:?Agent]![]+	 n3 [cat:vp idx:?Event]![]+	  {+	   n4 anchor [cat:v idx:?Event]![]+	  }+	}++vArity2:TrV(?Event ?Agent ?Experiencer ! agr:?A) initial+	n1[cat:s idx:?Event]![]+	{+	 n2 type:subst [cat:np idx:?Agent ]![]+	 n3[cat:vp idx:?Event]![]+	  {+	   n4 anchor [cat:v idx:?Event]![]+	   n6 type:subst [cat:np idx:?Experiencer ]![]+	  }+	}++vArity3:TrVPP(?Event ?Agent ?Theme ?Loc ! agr:?A) initial+	n1[cat:s idx:?Event]![]+	{+	  n2 type:subst [cat:np idx:?Agent ]![]+	  n3[cat:vp idx:?Event]![]+	  {+	    n4 anchor [cat:v idx:?Event]![]+	    n6 type:subst [cat:np idx:?Theme ]![]+	    n7 aconstr:noadj [cat:pp]![]+            {+	      n8[cat:p]![]+	      {+	        n9 type:lex "from"+	      }+	      n10 type:subst [cat:np idx:?Loc ]![]+	    }+	  }+	}++Dp(?Entity ! agr:?A) initial+	n1[cat:np idx:?Entity]![]+	{+	  n2 anchor [cat:det]![]+	  n4 type:subst [cat:n idx:?Entity ]![]+	}++Pn(?Entity ! agr:?A) initial+	n1[cat:np idx:?Entity]![]+	{+	 n2 anchor [cat:pn idx:?Entity]![]+	}++Cn(?Entity ! agr:?A) initial+	n1 anchor [cat:n idx:?Entity]![]++%% ?AUXILIARY ?TREES++Adj(?Entity) auxiliary+	n1[cat:n idx:?Entity]![]+	{+	  n2 anchor [cat:adj]![]+	  n4 type:foot [cat:n idx:?Entity ]![]+	}++Adv(?Event) auxiliary+	n1[cat:vp idx:?Event]![]+	{+	  n2 type:foot [cat:vp idx:?Event]![]+	  n3 anchor [cat:adv]![]+	}	
− examples/nosemantics/macros
@@ -1,363 +0,0 @@-%%-%% GENI Macro-%% This macro was automatically generated by-%% a tagml->macro script, tagml2genimacro.xsl-%% 2005-%% contact: kow@loria.fr lai@loria.fr--n() initial-n1 anchor--{-}--pro() initial-n1 anchor--{-}--pro_substantif() initial-n1 [cat:nom]![cat:nom]-{-n1.1 anchor-}--det_n() auxiliary-n1 [cat:nom]![cat:nom]-{-n1.1 anchor-n1.2 type:foot [cat:nom]![cat:nom]-}--n_la() auxiliary-n1 [cat:nom]![cat:nom]-{-n1.1 type:foot [cat:nom]![cat:nom]-n1.2 anchor-}--det_substantif() initial-n1 [cat:nom]![cat:nom]-{-n1.1 anchor-}--det_det() auxiliary-n1 [cat:det]![cat:det]-{-n1.1 type:foot [cat:det]![cat:det]-n1.2 anchor-}--np() initial-n1 anchor--{-}--np_substantif() initial-n1 [cat:nom]![cat:nom]-{-n1.1 anchor-}--n_np() auxiliary-n1 [cat:nom]![cat:nom]-{-n1.1 type:foot [cat:nom]![cat:nom]-n1.2 anchor-}--n_con_n() initial-n1 [cat:nom]![cat:nom]-{-n1.1 type:subst [cat:nom]![cat:nom]-n1.2 anchor-n1.3 type:subst [cat:nom]![cat:nom]-}--enum_n() auxiliary-n1 [cat:nom]![cat:nom]-{-n1.1 type:foot [cat:nom]![cat:nom]-n1.2 anchor-}--n_pred() initial-n1 [cat:nom]![cat:nom]-{-n1.1 type:subst [cat:nom]![cat:nom]-n1.2 [cat:gp]![cat:gp]-{-n1.2.1 anchor-n1.2.2 type:subst [cat:nom]![cat:nom]-}-}--compl_n() initial-n1 [cat:nom]![cat:nom]-{-n1.1 type:subst [cat:nom]![cat:nom]-n1.2 [cat:cdn]![cat:cdn]-{-n1.2.1 anchor-n1.2.2 type:subst [cat:nom]![cat:nom]-}-}--adj() initial-n1 anchor--{-}--adj_substantif() initial-n1 [cat:nom]![cat:nom]-{-n1.1 anchor-}--adv_adj() auxiliary-n1 [cat:adj]![cat:adj]-{-n1.1 anchor-n1.2 type:foot [cat:adj]![cat:adj]-}--adj_n() auxiliary-n1 [cat:nom]![cat:nom]-{-n1.1 anchor-n1.2 type:foot [cat:nom]![cat:nom]-}--n_adj() auxiliary-n1 [cat:nom]![cat:nom]-{-n1.1 type:foot [cat:nom]![cat:nom]-n1.2 anchor-}--n_gp() auxiliary-n1 [cat:nom]![cat:nom]-{-n1.1 type:foot [cat:nom]![cat:nom]-n1.2 [cat:gp]![cat:gp]-{-n1.2.1 anchor-n1.2.2 type:subst [cat:nom]![cat:nom]-}-}--s_gp() auxiliary-n1 [cat:sen]![cat:sen]-{-n1.1 type:foot [cat:sen]![cat:sen]-n1.2 [cat:gp]![cat:gp]-{-n1.2.1 anchor-n1.2.2 type:subst [cat:nom]![cat:nom]-}-}--gp_s() auxiliary-n1 [cat:sen]![cat:sen]-{-n1.1 type:foot [cat:sen]![cat:sen]-n1.2 [cat:gp]![cat:gp]-{-n1.2.1 anchor-n1.2.2 type:subst [cat:nom]![cat:nom]-}-}--gp() initial-n1 [cat:gp]![cat:gp]-{-n1.1 anchor-n1.2 type:subst [cat:nom]![cat:nom]-}--gpro() initial-n1 [cat:nom]![cat:nom]-{-n1.1 anchor-n1.2 type:subst [cat:nom]![cat:nom]-}--gpro_n_right() auxiliary-n1 [cat:nom]![cat:nom]-{-n1.1 type:foot [cat:nom]![cat:nom]-n1.2 anchor-n1.3 type:subst [cat:nom]![cat:nom]-}--n0_v() initial-n1 [cat:sen]![cat:sen]-{-n1.1 type:subst [cat:nom]![cat:nom]-n1.2 anchor-}--n0_v_n1() initial-n1 [cat:sen]![cat:sen]-{-n1.1 type:subst [cat:nom]![cat:nom]-n1.2 anchor-n1.3 type:subst [cat:nom]![cat:nom]-}--pro_v() initial-n1 [cat:sen]![cat:sen]-{-n1.1 type:subst [cat:pro]![cat:pro]-n1.2 anchor-}--pro_v_n1() initial-n1 [cat:sen]![cat:sen]-{-n1.1 type:subst [cat:pro]![cat:pro]-n1.2 anchor-n1.3 type:subst [cat:nom]![cat:nom]-}--v_inf() initial-n1 [cat:sen]![cat:sen]-{-n1.1 anchor-}--v_n1_inf() initial-n1 [cat:sen]![cat:sen]-{-n1.1 anchor-n1.2 type:subst [cat:nom]![cat:nom]-}--n0_v_s() initial-n1 [cat:sen]![cat:sen]-{-n1.1 type:subst [cat:nom]![cat:nom]-n1.2 anchor-n1.3 type:subst [cat:sen]![cat:sen]-}--pro_v_s() initial-n1 [cat:sen]![cat:sen]-{-n1.1 type:subst [cat:pro]![cat:pro]-n1.2 anchor-n1.3 type:subst [cat:sen]![cat:sen]-}--mod_v() auxiliary-n1 [cat:ver]![cat:ver]-{-n1.1 anchor-n1.2 type:foot [cat:ver]![cat:ver]-}--il_faut_n0() initial-n1 [cat:sen]![cat:sen]-{-n1.1 type:lex "il"-n1.2 anchor-n1.3 type:subst [cat:nom]![cat:nom]-}--mod_pro_left() auxiliary-n1 [cat:ver]![cat:ver]-{-n1.1 anchor-n1.2 type:foot [cat:ver]![cat:ver]-}--qu_est_ce_que() initial-n1 [cat:sen]![cat:sen]-{-n1.1 anchor-n1.2 type:subst [cat:sen]![cat:sen]-}--v_pro() initial-n1 [cat:sen]![cat:sen]-{-n1.1 anchor-n1.2 type:subst [cat:pro]![cat:pro]-}--v_pro_n() initial-n1 [cat:sen]![cat:sen]-{-n1.1 anchor-n1.2 type:subst [cat:pro]![cat:pro]-n1.3 type:subst [cat:nom]![cat:nom]-}--v_pro_s() initial-n1 [cat:sen]![cat:sen]-{-n1.1 anchor-n1.2 type:subst [cat:pro]![cat:pro]-n1.3 type:subst [cat:sen]![cat:sen]-}--mod_adv_left() auxiliary-n1 [cat:ver]![cat:ver]-{-n1.1 anchor-n1.2 type:foot [cat:ver]![cat:ver]-}--mod_adv_right() auxiliary-n1 [cat:ver]![cat:ver]-{-n1.1 type:foot [cat:ver]![cat:ver]-n1.2 anchor-}--mod_adv() auxiliary-n1 [cat:adv]![cat:adv]-{-n1.1 anchor-n1.2 type:foot [cat:adv]![cat:adv]-}--mod_adv_n_left() auxiliary-n1 [cat:nom]![cat:nom]-{-n1.1 type:foot [cat:nom]![cat:nom]-n1.2 anchor-}--mod_adv_n_right() auxiliary-n1 [cat:nom]![cat:nom]-{-n1.1 anchor-n1.2 type:foot [cat:nom]![cat:nom]-}--adv() initial-n1 anchor--{-}--entre_np_et_np() initial-n1 [cat:gp]![cat:gp]-{-n1.1 anchor-n1.2 type:subst [cat:nompropre]![cat:nompropre]-n1.3 type:lex "et"-n1.4 type:subst [cat:nompropre]![cat:nompropre]-}--int() initial-n1 anchor--{-}-
+ examples/nosemantics/trees view
@@ -0,0 +1,363 @@+%%+%% GENI Macro+%% This macro was automatically generated by+%% a tagml->macro script, tagml2genimacro.xsl+%% 2005+%% contact: kow@loria.fr lai@loria.fr++n() initial+n1 anchor++{+}++pro() initial+n1 anchor++{+}++pro_substantif() initial+n1 [cat:nom]![cat:nom]+{+n1.1 anchor+}++det_n() auxiliary+n1 [cat:nom]![cat:nom]+{+n1.1 anchor+n1.2 type:foot [cat:nom]![cat:nom]+}++n_la() auxiliary+n1 [cat:nom]![cat:nom]+{+n1.1 type:foot [cat:nom]![cat:nom]+n1.2 anchor+}++det_substantif() initial+n1 [cat:nom]![cat:nom]+{+n1.1 anchor+}++det_det() auxiliary+n1 [cat:det]![cat:det]+{+n1.1 type:foot [cat:det]![cat:det]+n1.2 anchor+}++np() initial+n1 anchor++{+}++np_substantif() initial+n1 [cat:nom]![cat:nom]+{+n1.1 anchor+}++n_np() auxiliary+n1 [cat:nom]![cat:nom]+{+n1.1 type:foot [cat:nom]![cat:nom]+n1.2 anchor+}++n_con_n() initial+n1 [cat:nom]![cat:nom]+{+n1.1 type:subst [cat:nom]![cat:nom]+n1.2 anchor+n1.3 type:subst [cat:nom]![cat:nom]+}++enum_n() auxiliary+n1 [cat:nom]![cat:nom]+{+n1.1 type:foot [cat:nom]![cat:nom]+n1.2 anchor+}++n_pred() initial+n1 [cat:nom]![cat:nom]+{+n1.1 type:subst [cat:nom]![cat:nom]+n1.2 [cat:gp]![cat:gp]+{+n1.2.1 anchor+n1.2.2 type:subst [cat:nom]![cat:nom]+}+}++compl_n() initial+n1 [cat:nom]![cat:nom]+{+n1.1 type:subst [cat:nom]![cat:nom]+n1.2 [cat:cdn]![cat:cdn]+{+n1.2.1 anchor+n1.2.2 type:subst [cat:nom]![cat:nom]+}+}++adj() initial+n1 anchor++{+}++adj_substantif() initial+n1 [cat:nom]![cat:nom]+{+n1.1 anchor+}++adv_adj() auxiliary+n1 [cat:adj]![cat:adj]+{+n1.1 anchor+n1.2 type:foot [cat:adj]![cat:adj]+}++adj_n() auxiliary+n1 [cat:nom]![cat:nom]+{+n1.1 anchor+n1.2 type:foot [cat:nom]![cat:nom]+}++n_adj() auxiliary+n1 [cat:nom]![cat:nom]+{+n1.1 type:foot [cat:nom]![cat:nom]+n1.2 anchor+}++n_gp() auxiliary+n1 [cat:nom]![cat:nom]+{+n1.1 type:foot [cat:nom]![cat:nom]+n1.2 [cat:gp]![cat:gp]+{+n1.2.1 anchor+n1.2.2 type:subst [cat:nom]![cat:nom]+}+}++s_gp() auxiliary+n1 [cat:sen]![cat:sen]+{+n1.1 type:foot [cat:sen]![cat:sen]+n1.2 [cat:gp]![cat:gp]+{+n1.2.1 anchor+n1.2.2 type:subst [cat:nom]![cat:nom]+}+}++gp_s() auxiliary+n1 [cat:sen]![cat:sen]+{+n1.1 type:foot [cat:sen]![cat:sen]+n1.2 [cat:gp]![cat:gp]+{+n1.2.1 anchor+n1.2.2 type:subst [cat:nom]![cat:nom]+}+}++gp() initial+n1 [cat:gp]![cat:gp]+{+n1.1 anchor+n1.2 type:subst [cat:nom]![cat:nom]+}++gpro() initial+n1 [cat:nom]![cat:nom]+{+n1.1 anchor+n1.2 type:subst [cat:nom]![cat:nom]+}++gpro_n_right() auxiliary+n1 [cat:nom]![cat:nom]+{+n1.1 type:foot [cat:nom]![cat:nom]+n1.2 anchor+n1.3 type:subst [cat:nom]![cat:nom]+}++n0_v() initial+n1 [cat:sen]![cat:sen]+{+n1.1 type:subst [cat:nom]![cat:nom]+n1.2 anchor+}++n0_v_n1() initial+n1 [cat:sen]![cat:sen]+{+n1.1 type:subst [cat:nom]![cat:nom]+n1.2 anchor+n1.3 type:subst [cat:nom]![cat:nom]+}++pro_v() initial+n1 [cat:sen]![cat:sen]+{+n1.1 type:subst [cat:pro]![cat:pro]+n1.2 anchor+}++pro_v_n1() initial+n1 [cat:sen]![cat:sen]+{+n1.1 type:subst [cat:pro]![cat:pro]+n1.2 anchor+n1.3 type:subst [cat:nom]![cat:nom]+}++v_inf() initial+n1 [cat:sen]![cat:sen]+{+n1.1 anchor+}++v_n1_inf() initial+n1 [cat:sen]![cat:sen]+{+n1.1 anchor+n1.2 type:subst [cat:nom]![cat:nom]+}++n0_v_s() initial+n1 [cat:sen]![cat:sen]+{+n1.1 type:subst [cat:nom]![cat:nom]+n1.2 anchor+n1.3 type:subst [cat:sen]![cat:sen]+}++pro_v_s() initial+n1 [cat:sen]![cat:sen]+{+n1.1 type:subst [cat:pro]![cat:pro]+n1.2 anchor+n1.3 type:subst [cat:sen]![cat:sen]+}++mod_v() auxiliary+n1 [cat:ver]![cat:ver]+{+n1.1 anchor+n1.2 type:foot [cat:ver]![cat:ver]+}++il_faut_n0() initial+n1 [cat:sen]![cat:sen]+{+n1.1 type:lex "il"+n1.2 anchor+n1.3 type:subst [cat:nom]![cat:nom]+}++mod_pro_left() auxiliary+n1 [cat:ver]![cat:ver]+{+n1.1 anchor+n1.2 type:foot [cat:ver]![cat:ver]+}++qu_est_ce_que() initial+n1 [cat:sen]![cat:sen]+{+n1.1 anchor+n1.2 type:subst [cat:sen]![cat:sen]+}++v_pro() initial+n1 [cat:sen]![cat:sen]+{+n1.1 anchor+n1.2 type:subst [cat:pro]![cat:pro]+}++v_pro_n() initial+n1 [cat:sen]![cat:sen]+{+n1.1 anchor+n1.2 type:subst [cat:pro]![cat:pro]+n1.3 type:subst [cat:nom]![cat:nom]+}++v_pro_s() initial+n1 [cat:sen]![cat:sen]+{+n1.1 anchor+n1.2 type:subst [cat:pro]![cat:pro]+n1.3 type:subst [cat:sen]![cat:sen]+}++mod_adv_left() auxiliary+n1 [cat:ver]![cat:ver]+{+n1.1 anchor+n1.2 type:foot [cat:ver]![cat:ver]+}++mod_adv_right() auxiliary+n1 [cat:ver]![cat:ver]+{+n1.1 type:foot [cat:ver]![cat:ver]+n1.2 anchor+}++mod_adv() auxiliary+n1 [cat:adv]![cat:adv]+{+n1.1 anchor+n1.2 type:foot [cat:adv]![cat:adv]+}++mod_adv_n_left() auxiliary+n1 [cat:nom]![cat:nom]+{+n1.1 type:foot [cat:nom]![cat:nom]+n1.2 anchor+}++mod_adv_n_right() auxiliary+n1 [cat:nom]![cat:nom]+{+n1.1 anchor+n1.2 type:foot [cat:nom]![cat:nom]+}++adv() initial+n1 anchor++{+}++entre_np_et_np() initial+n1 [cat:gp]![cat:gp]+{+n1.1 anchor+n1.2 type:subst [cat:nompropre]![cat:nompropre]+n1.3 type:lex "et"+n1.4 type:subst [cat:nompropre]![cat:nompropre]+}++int() initial+n1 anchor++{+}+
− examples/promettre/macros
@@ -1,450 +0,0 @@-%% 02 april 2004-%% 1. Jean promet un cadeau a Marie-%% 2. Jean promet a Marie de partir-%% 6. la personne qui promet un cadeau a Marie-%% 7. le cadeau que Jean promet a Marie-%% 8. la personne a qui Jean promet un cadeau-%% 9. promettre un cadeau a Marie-%% 10. promettant un cadeau a Marie-%% 11. donner un livre a marie--% FIXME: eric the non-linguist set all cat:p nodes with unspecified mode to FIXME--Det(?I) auxiliary-n1[cat:n idx:?I det:plus qu:minus]![cat:n idx:?I qu:minus]-{-  n2 type:anchor [cat:det]![]-  n4 type:foot [cat:n idx:?I]![cat:n idx:?I det:minus]-}--clitic:cl(?H ?X ! idx:?X ) initial-n1 type:anchor [cat:cl idx:?X]![cat:cl idx:?X] {}--pronoun:pn(?H ?X ! idx:?X num:?Num gen:?Gen pers:?Pers) initial-n1 [cat:n idx:?X num:?Num gen:?Gen pers:?Pers]![cat:n idx:?X]-{-  n2 type:anchor [cat:pn num:?Num gen:?Gen pers:?Pers]![] -}--% Common Nouns: voyage-nC(?I!num:?Num gen:?Gen) initial-n1 [cat:n num:?Num gen:?Gen idx:?I]![cat:n num:?Num gen:?Gen idx:?I det:minus qu:minus]-{-  n2 type:anchor [cat:n num:?Num gen:?Gen]![]-}--% Proper Nouns: Jean-nP(?I!pers:?Pers num:?Num gen:?Gen) initial-n1 type:anchor [cat:n num:?Num pers:?Pers gen:?Gen idx:?I det:plus qu:minus]![cat:n idx:?I det:plus qu:minus] {}----% jean se aimer -- note: we rely on top/bottom unification-% for this to work-vArity2:n0v(?E ?X ?Y) initial -n1[cat:p mode:FIXME]![]-{-  n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?Y]-  n5 [cat:se idx:?X det:plus qu:minus]![cat:se idx:?Y]-  n3 type:anchor [cat:v idx:?E]![]-}--vArity2:n0cl1v(?E ?X ?Y) initial-n1[cat:p mode:FIXME]![]-{-  n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X]-  n5 type:subst [cat:cl idx:?Y det:plus qu:minus]![cat:cl idx:?Y]-  n3 type:anchor [cat:v idx:?E]![]-}--vArity2:n0vn1(?E ?X ?Y) initial-n1[cat:p mode:FIXME]![]-{-  n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X]-  n3 type:anchor [cat:v idx:?E]![]-  n5 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y]-} --% aimer N (jean espere [aimer Marie])-vArity2:vinfn1(?E ?X ?Y) initial -n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p]-{-  n2 type:anchor [cat:v idx:?E]![]-  n4 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y]-}--% le aimer (jean espere [le aimer])-cl0vinf(?E ?X ?Y) initial -n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p]-{-  n5 type:subst [cat:cl idx:?Y det:plus qu:minus]![cat:cl idx:?Y]-  n2 type:anchor [cat:v idx:?E]![]-}--% infinitive: le donner un livre (je promets de le donner un livre)-vArity3:cl2vinfn0(?E ?X ?Y ?Z) initial -n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p]-{-  n5 type:subst [cat:cl idx:?Z det:plus qu:minus]![cat:cl idx:?Z]-  n2 type:anchor [cat:v idx:?E]![]-  n4 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y]-}  --  %1 declarative	gn promet gn sp_a-vArity3:n0vn1sp2(?E ?X ?Y ?Z) initial-n1[cat:p mode:FIXME]![]-{-  n2 type:subst [cat:n pers:?Pers num:?Num idx:?X det:plus qu:minus]![cat:n idx:?X]-  n3[cat:v idx:?E]![]-  {-    n4 type:anchor [cat:v pers:?Pers num:?Num]![] -  }-  n5 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y]-  n6[cat:sp idx:?Z det:plus]![]-  { n8[cat:prep]![]-    {-      n9 type:lex "a"-    }-    n10 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z] -  }-}---  %2 infinitive	?V GN SP_a-vArity3:vinfn1sp2(?E ?X ?Y ?Z) initial-n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p]-{-  n2 type:anchor [cat:v idx:?E]![]-  n4 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y]-  n5[cat:sp idx:?Z det:plus]![]-  { n6[cat:prep]![]-    {-      n7 type:lex "a"-    }-    n8 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z] -  }-}--vArity3:n0vn1inf2(?E ?X ?Y ?Z) initial-n1[cat:p mode:FIXME]![]-{-  n2 type:subst [cat:n idx:?X pers:?Pers num:?Num det:plus qu:minus]![cat:n idx:?X]-  n3[cat:v idx:?E]![]-  {-    n4 type:anchor [cat:v pers:?Pers num:?Num]![] -  }-  n5[cat:sp idx:?Z det:plus]![]-  { n6[cat:p]![]-    {-      n7 type:lex "a"-    }-    n8 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z-    ] -  }-  n9 type:subst [cat:p idx:?Y mode:inf]![cat:p idx:?Y] -}--%8 relative objet indirect-vArity3:rel2n0vn1(?E ?X ?Y ?Z) auxiliary-n0[cat:n idx:?Z det:plus]![cat:n idx:?Z]-{-  n1 type:foot [cat:n idx:?Z]![cat:n idx:?Z]-  n2[cat:p]![]-  {-    n3[cat:sp idx:?Z det:plus]![]-    { n4[cat:prep]![]-      {-        n5 type:lex "a"-      }-      n6 type:subst [cat:n idx:?Z det:plus qu:plus]![cat:n idx:?Z  qu:plus] -    }-    n7[cat:p idx:?E]![]-    {-      n8 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X  qu:minus]-      n9 type:anchor [cat:v idx:?E]![cat:p idx:?E]-      n11 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y]-    }-  }-}--  %9 declarative	GN V GN_a Pinf_de-vArity3control:n0vsp2pinf1(?E ?X ?Y ?Z) initial-n1[cat:p mode:FIXME]![]-{-  n2 type:subst [cat:n pers:?Pers num:?Num idx:?X det:plus qu:minus]![cat:n idx:?X]-  n3[cat:v idx:?E]![]-  {-    n4 type:anchor [cat:v pers:?Pers num:?Num]![]-  }-  n5[cat:sp idx:?Z det:plus]![]-  { n6[cat:prep]![]-    {-      n7 type:lex "a"-    }-    n8 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z] -  }-  n9[cat:p]![]-  {n10[cat:prep]![]-    {-      n11 type:lex "de"-    } -    n12 type:subst [cat:p idx:?Y mode:inf sujidx:?X]![cat:p idx:?Y]-  }-}--  %10 infinitive	V SP_a Inf_de-vArity3control:vinfsp2pinf1(?E ?X ?Y ?Z)  initial-n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p] -{-  n2 type:anchor [cat:v idx:?E]![]-  n4[cat:sp idx:?Y det:plus]![]-  { n5[cat:prep]![]-    {-      n6 type:lex "a"-    }-    n7 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y-    ] -  }-  n8[cat:p]![]-  {n9[cat:prep]![]-    {-      n10 type:lex "de"-    } -    n11 type:subst [cat:p idx:?Y mode:inf sujidx:?X]![cat:p idx:?Y]--  }-}--  % kowey: promettre a marie de faire...-vArity3control:vinfn2pinf1(?E ?X ?Y ?Z) initial-n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p] -{-  n2 type:anchor [cat:v idx:?E]![]--  n5[cat:sp idx:?Z det:plus]![]-  { n6[cat:prep]![]-    {-      n7 type:lex "a"-    }-    n8 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z] -  }--  n10[cat:p]![]-  {n11[cat:prep]![]-    {-      n12 type:lex "de"-    } -    n13 type:subst [cat:p idx:?Y mode:inf sujidx:?X]![cat:p idx:?Y]-  }-}--  %13 relative sujet	qui V sp_a pinf_de-vArity3control:rel0vsp2pinf1(?E ?X ?Y ?Z) auxiliary-n0[cat:n idx:?X det:plus]![cat:n idx:?X]-{-  n1 type:foot [cat:n idx:?X]![cat:n idx:?X]-  n2[cat:p]![]-  {-    n3 type:subst [cat:cl idx:?X det:plus qu:minus]![cat:cl idx:?X]-    n4 type:anchor [cat:v idx:?E]![]-    n6[cat:sp idx:?Y]![]-    { n7[cat:prep]![]-      {-        n8 type:lex "a"-      }-      n9 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n -      ] -    }-    n10[cat:p]![]-    {n11[cat:prep]![]-      {-        n12 type:lex "de"-      } -      n13 type:subst [cat:p idx:?Y mode:inf sujidx:?X]![cat:p idx:?Y]-    }}}---%14 relative objet indirect	a qui GN v Pinf_de-vArity3control:rel2n0vpinf1(?E ?X ?Y ?Z) auxiliary-n0[cat:n idx:?Y det:plus]![cat:n idx:?Y]-{-  n1 type:foot [cat:n idx:?Y]![cat:n idx:?Y]-  n2[cat:p]![]-  {-    n3[cat:sp idx:?Y det:plus]![]-    { n4[cat:prep]![]-      {-        n5 type:lex "a"-      }-      n6 type:subst [cat:n idx:?Y det:plus qu:plus]![cat:n idx:?Y  qu:plus] -    }-    n7[cat:p idx:?E]![]-    {-      n8 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X  qu:minus]-      n9 type:anchor [cat:v idx:?E]![cat:p idx:?E]-    }-    n9[cat:p]![]-    {n10[cat:prep]![]-      {-        n11 type:lex "de"-      } -      n12 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z]-    }-  }}---vArity3control:rel0vn2pinf1(?E ?X ?Y ?Z) auxiliary-n0[cat:n idx:?X det:plus]![cat:n idx:?X]-{-  n1 type:foot [cat:n idx:?X]![cat:n idx:?X]-  n2[cat:p]![]-  {-    n3 type:subst [cat:cl idx:?X det:plus qu:minus]![cat:n idx:?X]-    n4 type:anchor [cat:v idx:?E]![]-    n6 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n -    ] -    n7[cat:p]![]-    {n8[cat:prep]![]-      {-        n9 type:lex "de"-      } -      n10 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z]-    }}}--% relative sujet-vArity3control:rel0vn1sp2(?E ?X ?Y ?Z) auxiliary-n0[cat:n idx:?X det:plus]![cat:n idx:?X]-{-  n1 type:foot [cat:n idx:?X]![cat:n idx:?X]-  n2[cat:p]![]-  {-    n3 type:subst [cat:cl idx:?X det:plus qu:minus]![cat:n idx:?X]-    n4 type:anchor [cat:v idx:?E]![]-    n6 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z]-    n7[cat:sp idx:?Y]![]-    { n8[cat:p]![]-      {-        n9 type:lex "a"-      }-      n10 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n] -    }-  }-}--% relative objet-vArity3control:rel1vn0sp2(?E ?X ?Y ?Z) auxiliary-n0[cat:n idx:?X det:plus]![cat:n idx:?X]-{-  n1 type:foot [cat:n idx:?X]![cat:n idx:?X]-  n2[cat:p]![]-  {-    n3 type:subst [cat:cl idx:?X det:plus qu:minus]![cat:cl idx:?X]-    n4 type:anchor [cat:v idx:?E]![]-    n6 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z]-    n7[cat:sp idx:?Y]![]-    { n8[cat:p]![]-      {-        n9 type:lex "a"-      }-      n10 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n] -    }-  }-}--  % relative objet indirect-rel2vn0n1(?E ?X ?Y ?Z) auxiliary-n0[cat:n idx:?Y det:plus]![cat:n idx:?Y]-{-  n1 type:foot [cat:n idx:?Y]![cat:n idx:?Y]-  n2[cat:p]![]-  {-    n3[cat:sp idx:?Y det:plus]![]-    { n4[cat:p]![]-      {-        n5 type:lex "a"-      }-      n6 type:subst [cat:n idx:?Y det:plus qu:plus]![cat:n idx:?Y  qu:plus] -    }-    n7[cat:p idx:?E]![]-    {-      n8 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X  qu:minus]-      n9 type:anchor [cat:v idx:?E]![cat:p idx:?E]-      n11 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z]-    }-  }-}--  % kowey: for persuader instead of promettre-  % (sujidx is set differently)-vArity3controlObj:n0vsp2pinf1b(?E ?X ?Y ?Z) initial-n1[cat:p mode:FIXME]![]-{-  n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X]-  n3 type:anchor [cat:v idx:?E]![]-  n5[cat:sp idx:?Z det:plus]![]-  { n6[cat:prep]![]-    {-      n7 type:lex "a"-    }-    n8 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z] -  }-  n9[cat:p]![]-  {n10[cat:prep]![]-    {-      n11 type:lex "de"-    } -    n12 type:subst [cat:p idx:?Y mode:inf sujidx:?Z]![cat:p idx:?Y]-  }-}--  %15 declarative gn0 persuade gn2 pinf_de1	n0vn2pinf1 -vArity3controlObj:n0vn2pinf1b(?E ?X ?Y ?Z) initial-n1[cat:p mode:FIXME]![]-{-  n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X]-  n3 type:anchor [cat:v idx:?E]![]-  n5 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z]-  n6[cat:p]![]-  {n7[cat:prep]![]-    {-      n8 type:lex "de"-    } -    n9 type:subst [cat:p idx:?Y mode:inf sujidx:?Z]![cat:p idx:?Y] -  }-}--  %15 infinitive persuader gn  pinf_de	vinfn2pinf1-vArity3controlObj:vinfn2pinf1b(?E ?X ?Y ?Z) initial-n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p] -{-  n2 type:anchor [cat:v idx:?E]![]-  n4 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z] -  n5[cat:p]![]-  {n6[cat:prep]![]-    {-      n7 type:lex "de"-    } -    n8 type:subst [cat:p idx:?Y mode:inf sujidx:?Z]![cat:p idx:?Y]-  }-}--  %18 rel-sjt	 n qui persuade gn  pinf_de	rel0vn2pinf1-vArity3controlObj:n0vn1sp2(?E ?X ?Y ?Z) initial-n1[cat:p mode:FIXME]![]-{-  n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X]-  n3 type:anchor [cat:v idx:?E]![]-  n5 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y]-  n6[cat:sp idx:?Z det:plus]![]-  { n8[cat:p]![]-    {-      n9 type:lex "a"-    }-    n10 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z-    ] -  }-}--% vi: set cinoptions=0,p0:--
+ examples/promettre/trees view
@@ -0,0 +1,450 @@+%% 02 april 2004+%% 1. Jean promet un cadeau a Marie+%% 2. Jean promet a Marie de partir+%% 6. la personne qui promet un cadeau a Marie+%% 7. le cadeau que Jean promet a Marie+%% 8. la personne a qui Jean promet un cadeau+%% 9. promettre un cadeau a Marie+%% 10. promettant un cadeau a Marie+%% 11. donner un livre a marie++% FIXME: eric the non-linguist set all cat:p nodes with unspecified mode to FIXME++Det(?I) auxiliary+n1[cat:n idx:?I det:plus qu:minus]![cat:n idx:?I qu:minus]+{+  n2 type:anchor [cat:det]![]+  n4 type:foot [cat:n idx:?I]![cat:n idx:?I det:minus]+}++clitic:cl(?H ?X ! idx:?X ) initial+n1 type:anchor [cat:cl idx:?X]![cat:cl idx:?X] {}++pronoun:pn(?H ?X ! idx:?X num:?Num gen:?Gen pers:?Pers) initial+n1 [cat:n idx:?X num:?Num gen:?Gen pers:?Pers]![cat:n idx:?X]+{+  n2 type:anchor [cat:pn num:?Num gen:?Gen pers:?Pers]![] +}++% Common Nouns: voyage+nC(?I!num:?Num gen:?Gen) initial+n1 [cat:n num:?Num gen:?Gen idx:?I]![cat:n num:?Num gen:?Gen idx:?I det:minus qu:minus]+{+  n2 type:anchor [cat:n num:?Num gen:?Gen]![]+}++% Proper Nouns: Jean+nP(?I!pers:?Pers num:?Num gen:?Gen) initial+n1 type:anchor [cat:n num:?Num pers:?Pers gen:?Gen idx:?I det:plus qu:minus]![cat:n idx:?I det:plus qu:minus] {}++++% jean se aimer -- note: we rely on top/bottom unification+% for this to work+vArity2:n0v(?E ?X ?Y) initial +n1[cat:p mode:FIXME]![]+{+  n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?Y]+  n5 [cat:se idx:?X det:plus qu:minus]![cat:se idx:?Y]+  n3 type:anchor [cat:v idx:?E]![]+}++vArity2:n0cl1v(?E ?X ?Y) initial+n1[cat:p mode:FIXME]![]+{+  n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X]+  n5 type:subst [cat:cl idx:?Y det:plus qu:minus]![cat:cl idx:?Y]+  n3 type:anchor [cat:v idx:?E]![]+}++vArity2:n0vn1(?E ?X ?Y) initial+n1[cat:p mode:FIXME]![]+{+  n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X]+  n3 type:anchor [cat:v idx:?E]![]+  n5 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y]+} ++% aimer N (jean espere [aimer Marie])+vArity2:vinfn1(?E ?X ?Y) initial +n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p]+{+  n2 type:anchor [cat:v idx:?E]![]+  n4 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y]+}++% le aimer (jean espere [le aimer])+cl0vinf(?E ?X ?Y) initial +n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p]+{+  n5 type:subst [cat:cl idx:?Y det:plus qu:minus]![cat:cl idx:?Y]+  n2 type:anchor [cat:v idx:?E]![]+}++% infinitive: le donner un livre (je promets de le donner un livre)+vArity3:cl2vinfn0(?E ?X ?Y ?Z) initial +n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p]+{+  n5 type:subst [cat:cl idx:?Z det:plus qu:minus]![cat:cl idx:?Z]+  n2 type:anchor [cat:v idx:?E]![]+  n4 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y]+}  ++  %1 declarative	gn promet gn sp_a+vArity3:n0vn1sp2(?E ?X ?Y ?Z) initial+n1[cat:p mode:FIXME]![]+{+  n2 type:subst [cat:n pers:?Pers num:?Num idx:?X det:plus qu:minus]![cat:n idx:?X]+  n3[cat:v idx:?E]![]+  {+    n4 type:anchor [cat:v pers:?Pers num:?Num]![] +  }+  n5 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y]+  n6[cat:sp idx:?Z det:plus]![]+  { n8[cat:prep]![]+    {+      n9 type:lex "a"+    }+    n10 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z] +  }+}+++  %2 infinitive	?V GN SP_a+vArity3:vinfn1sp2(?E ?X ?Y ?Z) initial+n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p]+{+  n2 type:anchor [cat:v idx:?E]![]+  n4 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y]+  n5[cat:sp idx:?Z det:plus]![]+  { n6[cat:prep]![]+    {+      n7 type:lex "a"+    }+    n8 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z] +  }+}++vArity3:n0vn1inf2(?E ?X ?Y ?Z) initial+n1[cat:p mode:FIXME]![]+{+  n2 type:subst [cat:n idx:?X pers:?Pers num:?Num det:plus qu:minus]![cat:n idx:?X]+  n3[cat:v idx:?E]![]+  {+    n4 type:anchor [cat:v pers:?Pers num:?Num]![] +  }+  n5[cat:sp idx:?Z det:plus]![]+  { n6[cat:p]![]+    {+      n7 type:lex "a"+    }+    n8 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z+    ] +  }+  n9 type:subst [cat:p idx:?Y mode:inf]![cat:p idx:?Y] +}++%8 relative objet indirect+vArity3:rel2n0vn1(?E ?X ?Y ?Z) auxiliary+n0[cat:n idx:?Z det:plus]![cat:n idx:?Z]+{+  n1 type:foot [cat:n idx:?Z]![cat:n idx:?Z]+  n2[cat:p]![]+  {+    n3[cat:sp idx:?Z det:plus]![]+    { n4[cat:prep]![]+      {+        n5 type:lex "a"+      }+      n6 type:subst [cat:n idx:?Z det:plus qu:plus]![cat:n idx:?Z  qu:plus] +    }+    n7[cat:p idx:?E]![]+    {+      n8 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X  qu:minus]+      n9 type:anchor [cat:v idx:?E]![cat:p idx:?E]+      n11 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y]+    }+  }+}++  %9 declarative	GN V GN_a Pinf_de+vArity3control:n0vsp2pinf1(?E ?X ?Y ?Z) initial+n1[cat:p mode:FIXME]![]+{+  n2 type:subst [cat:n pers:?Pers num:?Num idx:?X det:plus qu:minus]![cat:n idx:?X]+  n3[cat:v idx:?E]![]+  {+    n4 type:anchor [cat:v pers:?Pers num:?Num]![]+  }+  n5[cat:sp idx:?Z det:plus]![]+  { n6[cat:prep]![]+    {+      n7 type:lex "a"+    }+    n8 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z] +  }+  n9[cat:p]![]+  {n10[cat:prep]![]+    {+      n11 type:lex "de"+    } +    n12 type:subst [cat:p idx:?Y mode:inf sujidx:?X]![cat:p idx:?Y]+  }+}++  %10 infinitive	V SP_a Inf_de+vArity3control:vinfsp2pinf1(?E ?X ?Y ?Z)  initial+n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p] +{+  n2 type:anchor [cat:v idx:?E]![]+  n4[cat:sp idx:?Y det:plus]![]+  { n5[cat:prep]![]+    {+      n6 type:lex "a"+    }+    n7 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y+    ] +  }+  n8[cat:p]![]+  {n9[cat:prep]![]+    {+      n10 type:lex "de"+    } +    n11 type:subst [cat:p idx:?Y mode:inf sujidx:?X]![cat:p idx:?Y]++  }+}++  % kowey: promettre a marie de faire...+vArity3control:vinfn2pinf1(?E ?X ?Y ?Z) initial+n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p] +{+  n2 type:anchor [cat:v idx:?E]![]++  n5[cat:sp idx:?Z det:plus]![]+  { n6[cat:prep]![]+    {+      n7 type:lex "a"+    }+    n8 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z] +  }++  n10[cat:p]![]+  {n11[cat:prep]![]+    {+      n12 type:lex "de"+    } +    n13 type:subst [cat:p idx:?Y mode:inf sujidx:?X]![cat:p idx:?Y]+  }+}++  %13 relative sujet	qui V sp_a pinf_de+vArity3control:rel0vsp2pinf1(?E ?X ?Y ?Z) auxiliary+n0[cat:n idx:?X det:plus]![cat:n idx:?X]+{+  n1 type:foot [cat:n idx:?X]![cat:n idx:?X]+  n2[cat:p]![]+  {+    n3 type:subst [cat:cl idx:?X det:plus qu:minus]![cat:cl idx:?X]+    n4 type:anchor [cat:v idx:?E]![]+    n6[cat:sp idx:?Y]![]+    { n7[cat:prep]![]+      {+        n8 type:lex "a"+      }+      n9 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n +      ] +    }+    n10[cat:p]![]+    {n11[cat:prep]![]+      {+        n12 type:lex "de"+      } +      n13 type:subst [cat:p idx:?Y mode:inf sujidx:?X]![cat:p idx:?Y]+    }}}+++%14 relative objet indirect	a qui GN v Pinf_de+vArity3control:rel2n0vpinf1(?E ?X ?Y ?Z) auxiliary+n0[cat:n idx:?Y det:plus]![cat:n idx:?Y]+{+  n1 type:foot [cat:n idx:?Y]![cat:n idx:?Y]+  n2[cat:p]![]+  {+    n3[cat:sp idx:?Y det:plus]![]+    { n4[cat:prep]![]+      {+        n5 type:lex "a"+      }+      n6 type:subst [cat:n idx:?Y det:plus qu:plus]![cat:n idx:?Y  qu:plus] +    }+    n7[cat:p idx:?E]![]+    {+      n8 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X  qu:minus]+      n9 type:anchor [cat:v idx:?E]![cat:p idx:?E]+    }+    n9[cat:p]![]+    {n10[cat:prep]![]+      {+        n11 type:lex "de"+      } +      n12 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z]+    }+  }}+++vArity3control:rel0vn2pinf1(?E ?X ?Y ?Z) auxiliary+n0[cat:n idx:?X det:plus]![cat:n idx:?X]+{+  n1 type:foot [cat:n idx:?X]![cat:n idx:?X]+  n2[cat:p]![]+  {+    n3 type:subst [cat:cl idx:?X det:plus qu:minus]![cat:n idx:?X]+    n4 type:anchor [cat:v idx:?E]![]+    n6 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n +    ] +    n7[cat:p]![]+    {n8[cat:prep]![]+      {+        n9 type:lex "de"+      } +      n10 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z]+    }}}++% relative sujet+vArity3control:rel0vn1sp2(?E ?X ?Y ?Z) auxiliary+n0[cat:n idx:?X det:plus]![cat:n idx:?X]+{+  n1 type:foot [cat:n idx:?X]![cat:n idx:?X]+  n2[cat:p]![]+  {+    n3 type:subst [cat:cl idx:?X det:plus qu:minus]![cat:n idx:?X]+    n4 type:anchor [cat:v idx:?E]![]+    n6 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z]+    n7[cat:sp idx:?Y]![]+    { n8[cat:p]![]+      {+        n9 type:lex "a"+      }+      n10 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n] +    }+  }+}++% relative objet+vArity3control:rel1vn0sp2(?E ?X ?Y ?Z) auxiliary+n0[cat:n idx:?X det:plus]![cat:n idx:?X]+{+  n1 type:foot [cat:n idx:?X]![cat:n idx:?X]+  n2[cat:p]![]+  {+    n3 type:subst [cat:cl idx:?X det:plus qu:minus]![cat:cl idx:?X]+    n4 type:anchor [cat:v idx:?E]![]+    n6 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z]+    n7[cat:sp idx:?Y]![]+    { n8[cat:p]![]+      {+        n9 type:lex "a"+      }+      n10 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n] +    }+  }+}++  % relative objet indirect+rel2vn0n1(?E ?X ?Y ?Z) auxiliary+n0[cat:n idx:?Y det:plus]![cat:n idx:?Y]+{+  n1 type:foot [cat:n idx:?Y]![cat:n idx:?Y]+  n2[cat:p]![]+  {+    n3[cat:sp idx:?Y det:plus]![]+    { n4[cat:p]![]+      {+        n5 type:lex "a"+      }+      n6 type:subst [cat:n idx:?Y det:plus qu:plus]![cat:n idx:?Y  qu:plus] +    }+    n7[cat:p idx:?E]![]+    {+      n8 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X  qu:minus]+      n9 type:anchor [cat:v idx:?E]![cat:p idx:?E]+      n11 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z]+    }+  }+}++  % kowey: for persuader instead of promettre+  % (sujidx is set differently)+vArity3controlObj:n0vsp2pinf1b(?E ?X ?Y ?Z) initial+n1[cat:p mode:FIXME]![]+{+  n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X]+  n3 type:anchor [cat:v idx:?E]![]+  n5[cat:sp idx:?Z det:plus]![]+  { n6[cat:prep]![]+    {+      n7 type:lex "a"+    }+    n8 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z] +  }+  n9[cat:p]![]+  {n10[cat:prep]![]+    {+      n11 type:lex "de"+    } +    n12 type:subst [cat:p idx:?Y mode:inf sujidx:?Z]![cat:p idx:?Y]+  }+}++  %15 declarative gn0 persuade gn2 pinf_de1	n0vn2pinf1 +vArity3controlObj:n0vn2pinf1b(?E ?X ?Y ?Z) initial+n1[cat:p mode:FIXME]![]+{+  n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X]+  n3 type:anchor [cat:v idx:?E]![]+  n5 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z]+  n6[cat:p]![]+  {n7[cat:prep]![]+    {+      n8 type:lex "de"+    } +    n9 type:subst [cat:p idx:?Y mode:inf sujidx:?Z]![cat:p idx:?Y] +  }+}++  %15 infinitive persuader gn  pinf_de	vinfn2pinf1+vArity3controlObj:vinfn2pinf1b(?E ?X ?Y ?Z) initial+n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p] +{+  n2 type:anchor [cat:v idx:?E]![]+  n4 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z] +  n5[cat:p]![]+  {n6[cat:prep]![]+    {+      n7 type:lex "de"+    } +    n8 type:subst [cat:p idx:?Y mode:inf sujidx:?Z]![cat:p idx:?Y]+  }+}++  %18 rel-sjt	 n qui persuade gn  pinf_de	rel0vn2pinf1+vArity3controlObj:n0vn1sp2(?E ?X ?Y ?Z) initial+n1[cat:p mode:FIXME]![]+{+  n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X]+  n3 type:anchor [cat:v idx:?E]![]+  n5 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y]+  n6[cat:sp idx:?Z det:plus]![]+  { n8[cat:p]![]+    {+      n9 type:lex "a"+    }+    n10 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z+    ] +  }+}++% vi: set cinoptions=0,p0:++
examples/xmg-example/Makefile view
@@ -15,12 +15,12 @@ SUITE_LEXICON:=$(LEXICON_DIR)/$(FULL_LEXICON_PREFIX).lex SUITE_MORPH:=$(LEXICON_DIR)/$(MORPH_PREFIX).mph -GENI_GRAMMAR:=$(COMPILED_GRAMMAR_DIR)/$(GRAMMAR).genib+GENI_GRAMMAR:=$(COMPILED_GRAMMAR_DIR)/$(GRAMMAR).geni GENI_LEXICON:=$(LEXICON_DIR)/$(FULL_LEXICON_PREFIX).glex GENI_MORPH:=$(LEXICON_DIR)/$(MORPH_PREFIX).gmorph GENI_SUITE:=suite -GENI_OPTIMISATIONS:='pol f-sem'+GENI_OPTIMISATIONS:='pol'  GENI_LEX_FLAGS:=-l $(GENI_LEXICON) -s $(GENI_SUITE) ifdef ENABLE_MORPH@@ -59,7 +59,7 @@ NEW_DERIVATIONS:=new-derivations  run: $(GENI_GRAMMAR) lexicon morph-	$(GENI) -m $< $(GENI_FLAGS) --nogui --batchdir=results+	$(GENI) -m $< $(GENI_FLAGS) --nogui --batchdir=results --rootfeat='[cat:s]'  # -------------------------------------------------------------------- # running GenI@@ -109,11 +109,7 @@  %.geni : %.xml 	$(ECHO_STATUS) "converting to geni text format: $(basename $<)"-	$(SILENTLY) geniconvert -f tagml -t geni $< -o $@--%.genib : %.geni-	$(ECHO_STATUS) "converting to geni binary format: $<"-	$(SILENTLY) geniconvert -f geni -t genib $< -o $@+	$(SILENTLY) xsltproc  -o $@ xmg2geni.xsl $<  # -------------------------------------------------------------------- # lexicon
+ geni-test/MainTest.hs view
@@ -0,0 +1,5 @@+module Main where++import NLP.GenI.Test++main = runTests
+ geni-test/NLP/GenI/Test.hs view
@@ -0,0 +1,53 @@+-- ----------------------------------------------------------------------+-- GenI surface realiser+-- Copyright (C) 2009 Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.+-- ----------------------------------------------------------------------++module NLP.GenI.Test where++import Data.List ( isPrefixOf )+import System.Environment ( getArgs )++import Test.Framework++import NLP.GenI.Test.FeatureStructure ( suite )+import NLP.GenI.Test.Parser ( suite )+import NLP.GenI.Test.GeniVal ( suite )+import NLP.GenI.Test.LexicalSelection ( suite )+import NLP.GenI.Test.Lexicon ( suite )+import NLP.GenI.Test.Morphology ( suite )+import NLP.GenI.Test.Polarity ( suite )+import NLP.GenI.Test.Semantics ( suite )+import NLP.GenI.Test.Simple.SimpleBuilder ( suite )+import NLP.GenI.Regression++runTests :: IO ()+runTests = do+    args <- filter (not . (`isPrefixOf` "--unit-tests")) `fmap` getArgs+    funcSuite <- NLP.GenI.Regression.mkSuite+    flip defaultMainWithArgs args+        [ NLP.GenI.Test.GeniVal.suite+        , NLP.GenI.Test.Parser.suite+        , NLP.GenI.Test.FeatureStructure.suite+        , NLP.GenI.Test.LexicalSelection.suite+        , NLP.GenI.Test.Lexicon.suite+        , NLP.GenI.Test.Morphology.suite+        , NLP.GenI.Test.Polarity.suite+        , NLP.GenI.Test.Semantics.suite+        , NLP.GenI.Test.Simple.SimpleBuilder.suite+        , funcSuite+        ]
+ geni/geni.hs view
@@ -0,0 +1,20 @@+-- GenI surface realiser+-- Copyright (C) 2005 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.++module Main (module NLP.GenI.Main) where++import NLP.GenI.Main
+ src/BoolExp.hs view
@@ -0,0 +1,12 @@+module BoolExp where++data BoolExp a = Cond a+               | And (BoolExp a) (BoolExp a)+               | Or  (BoolExp a) (BoolExp a)+               | Not (BoolExp a)++check :: (a -> Bool) -> BoolExp a -> Bool+check f (Cond x)  = f x+check f (And x y) = check f x && check f y+check f (Or x y)  = check f x || check f y+check f (Not x)   = not (check f x)
+ src/Data/FullList.hs view
@@ -0,0 +1,14 @@+{-# OPTIONS_GHC -fno-warn-unused-imports #-}+module Data.FullList+   (FullList,+    fromFL,+    indeedFL,+    head,+    tail,+    (++),+    sortNub,+    Listable (..)+    ) where++import Data.FullList.Internal+import Prelude hiding ( head, tail, (++) )
+ src/Data/FullList/Internal.hs view
@@ -0,0 +1,80 @@+{-# LANGUAGE DeriveDataTypeable #-}++-- from http://www.haskell.org/haskellwiki/Non-empty_list+-- Safe list functions++module Data.FullList.Internal where++import Data.Binary+import Control.DeepSeq+import Prelude hiding (head, tail, (++))+import qualified Prelude+import Data.Data+import Data.List ( sort, nub )++newtype FullList a = FullList [a]  -- data constructor is not exported!+  deriving (Eq, Ord, Show, Data, Typeable)++fromFL :: FullList a -> [a]+fromFL (FullList x) = x                 -- Injection into general lists++-- The following is an analogue of `maybe'+indeedFL :: [a] -> w -> (FullList a -> w) -> w+indeedFL x on_empty on_full+    | null x = on_empty+    | otherwise = on_full $ FullList x++-- The following are _total_ functions+-- They are guaranteed to be safe, and so we could have used+-- unsafeHead# and unsafeTail# if GHC provides though...++head :: FullList a -> a+head (FullList (x:_)) = x+head (FullList _) = error "NList.head is broken"++tail :: FullList a -> [a]+tail (FullList (_:x)) = x+tail (FullList _) = error "NList.tail is broken"++(++) :: FullList a -> FullList a -> FullList a+(++) x y = FullList ((Prelude.++) (fromFL x) (fromFL y)) -- OK because both already full++sortNub :: (Eq a, Ord a) => FullList a -> FullList a+sortNub xs =+  case (sort . nub . fromFL $ xs) of+   []     -> error "sortNub is broken"+   (y:ys) -> y !: ys++-- Mapping over a non-empty list gives a non-empty list+instance Functor FullList where+    fmap f (FullList x) = FullList (map f x)++-- Adding something to a general list surely gives a non-empty list+infixr 5 !:++class Listable l where+    (!:) :: a -> l a -> FullList a++instance Listable [] where+    (!:) h t = FullList (h:t)++instance Listable FullList where+    (!:) h (FullList t) = FullList (h:t)++{-!+deriving instance NFData a => NFData (FullList a)+deriving instance Binary a => Binary (FullList a)+!-}+-- GENERATED START+++instance (NFData a) => NFData (FullList a) where+        rnf (FullList x1) = rnf x1 `seq` ()+++instance (Binary a) => Binary (FullList a) where+        put (FullList x1) = put x1+        get+          = do x1 <- get+               return (FullList x1)+-- GENERATED STOP
− src/MainGeni.lhs
@@ -1,126 +0,0 @@-% GenI surface realiser-% Copyright (C) 2005 Carlos Areces and Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.--\chapter{Main}--Welcome to the GenI source code.  The main module is where everything-starts from.  If you're trying to figure out how GenI works, the main-action is in Geni and Tags -(chapters \ref{cha:Geni} and \ref{cha:Tags}).  --\begin{code}-module Main (main) where-\end{code}--\ignore{-\begin{code}-import Control.Applicative ((<$>))-import Data.IORef(newIORef)-import Data.Typeable( Typeable )-import Data.Version ( showVersion )-import System.Environment(getArgs, getProgName)--import Paths_GenI ( version )--import NLP.GenI.Geni(emptyProgState)-import NLP.GenI.Console(consoleGeni)-import NLP.GenI.Configuration (treatArgs, optionsForStandardGenI, processInstructions,-                               usage, optionsSections, Params,-                               hasFlagP, BatchDirFlg(..), DisableGuiFlg(..),-                               DumpDerivationFlg(..),  FromStdinFlg(..),-                               HelpFlg(..), VersionFlg(..), TestCaseFlg(..),-                               RegressionTestModeFlg(..), RunUnitTestFlg(..),-                              )-import NLP.GenI.Regression (regressionGeni)-import NLP.GenI.Test (runTests)--#ifdef DISABLE_GUI-import NLP.GenI.Configuration(setFlagP)-import NLP.GenI.Geni(ProgStateRef)-#else-import NLP.GenI.Gui(guiGeni)-#endif--#ifdef DISABLE_GUI-guiGeni :: ProgStateRef -> IO ()-guiGeni = consoleGeni-#endif-\end{code}-}--In figure \ref{fig:code-outline-main} we show what happens from main: First, we-hand control off to either the console or the graphical user interface.  These-functions then do all the business stuff like loading files and figuring out-what to generate.  From there, they invoke the the generation step-\fnref{runGeni} which does surface realisation from A-Z.  Alternately, the-graphical interface could invoke a graphical debugger which also does surface-realisation from A-Z but allows you to intervene, inspect and stop at each-step.--\begin{figure}-\begin{center}-\includegraphics[scale=0.25]{images/code-outline-main}-\label{fig:code-outline-main}-\caption{How the GenI entry point is used}-\end{center}-\end{figure}--\begin{code}-main :: IO ()-main = do       -  pname <- getProgName-  args  <- getArgs-  confArgs <- forceGuiFlag <$> (processInstructions =<< treatArgs optionsForStandardGenI args)-  let pst = emptyProgState confArgs-  pstRef <- newIORef pst-  let has :: (Typeable f, Typeable x) => (x -> f) -> Bool-      has = flip hasFlagP confArgs-      mustRunInConsole = has DumpDerivationFlg || has FromStdinFlg || has BatchDirFlg-      canRunInConsole  = has TestCaseFlg-  case () of-   _ | has HelpFlg               -> putStrLn (usage optionsSections pname)-     | has VersionFlg            -> putStrLn ("GenI " ++ showVersion version)-     | has RunUnitTestFlg        -> runTests-     | has RegressionTestModeFlg -> regressionGeni pstRef-     | mustRunInConsole          -> consoleGeni pstRef-     | not (has DisableGuiFlg)   -> guiGeni pstRef-     | canRunInConsole           -> consoleGeni pstRef-     | otherwise                 -> fail $ unlines-        [ "GenI must either be run..."-        , " - with the graphical interface enabled"-        , " - in regression testing mode"-        , " - in self-diagnostic unit test mode"-        , " - with a test case specified"-        , " - with a batch directory specified or"-        , " - with --dump"-        , " - with --from-stdin"-        ]--forceGuiFlag :: Params -> Params-#ifdef DISABLE_GUI-forceGuiFlag = setFlagP DisableGuiFlg ()-#else-forceGuiFlag = id-#endif-\end{code}--% TODO-% Define what is and what is not exported from the modules.  -%      In particular in BTypes take care to export the inspection function -%      but not the types.-%      Re-write functions in Main as needed.-% Change input in Lexicon and Grammar to allow more than one anchor.
+ src/NLP/GenI.hs view
@@ -0,0 +1,872 @@+-- GenI surface realiser+-- Copyright (C) 2005 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.++{-# LANGUAGE ScopedTypeVariables, ExistentialQuantification, TypeSynonymInstances #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE OverloadedStrings #-}++-- | This is the interface between the front and backends of the generator. The GUI+--   and the console interface both talk to this module, and in turn, this module+--   talks to the input file parsers and the surface realisation engine.+module NLP.GenI (+             -- * Main interface++             -- ** Program state and configuration+             ProgState(..), ProgStateRef, emptyProgState,+             LexicalSelector,++             -- ** Running GenI+             runGeni,+             GeniResults(..),+             GeniResult(..), isSuccess, GeniError(..), GeniSuccess(..),+             GeniLexSel(..),+             ResultType(..),++             -- * Helpers+             initGeni, extractResults,+             lemmaSentenceString, prettyResult,+             showRealisations, histogram,+             getTraces,++             -- ** Loading things+             loadEverything,+             Loadable(..),+             loadLexicon,+             loadGeniMacros,+             loadTestSuite, parseSemInput,+             loadRanking, BadInputException(..),+             loadFromString,+             )+where+++import Control.Applicative ((<$>),(<*>))+import Control.DeepSeq+import Control.Exception+import Control.Monad.Error+import Data.Binary (Binary, decodeFile)+import Data.IORef (IORef, readIORef, modifyIORef)+import Data.List+import Data.Maybe (fromMaybe)+import Data.Monoid ( mappend, mempty )+import Data.Text ( Text )+import Data.Typeable (Typeable)+import System.CPUTime( getCPUTime )+import System.IO ( stderr )+import qualified Data.Map as Map+import qualified Data.Text as T+import qualified Data.Text.IO as T++import Data.FullList ( fromFL )+import Text.JSON+import qualified System.IO.UTF8 as UTF8++import NLP.GenI.Configuration+    ( Params, customMorph, customSelector+    , getFlagP, hasFlagP, hasOpt, Optimisation(NoConstraints)+    , MacrosFlg(..), LexiconFlg(..), TestSuiteFlg(..)+    , MorphInfoFlg(..), MorphCmdFlg(..)+    , RankingConstraintsFlg(..)+    , PartialFlg(..)+    , FromStdinFlg(..), VerboseModeFlg(..)+    , NoLoadTestSuiteFlg(..)+    , RootFeatureFlg(..)+    , TracesFlg(..)+    , grammarType+    , GrammarType(..)+    )+import NLP.GenI.General+    ( histogram, geniBug, snd3, first3, ePutStr, ePutStrLn, eFlush,+    -- mkLogname,+    )+import NLP.GenI.GeniVal+import NLP.GenI.LexicalSelection ( LexicalSelector, LexicalSelection(..), defaultLexicalSelector )+import NLP.GenI.Lexicon+import NLP.GenI.Morphology+import NLP.GenI.OptimalityTheory+import NLP.GenI.Parser (geniMacros, geniTagElems,+                    geniLexicon, geniTestSuite,+                    geniTestSuiteString, geniSemanticInput,+                    geniMorphInfo,+                    runParser,+                    ParseError,+                    )+import NLP.GenI.Pretty+import NLP.GenI.Semantics+import NLP.GenI.Statistics+import NLP.GenI.Tag ( TagElem, idname, tsemantics, ttrace, setTidnums )+import NLP.GenI.TestSuite ( TestCase(..) )+import NLP.GenI.TreeSchema+import NLP.GenI.Warning+import qualified NLP.GenI.Builder as B++-- -- DEBUG+-- import Control.Monad.Writer+-- import NLP.GenI.Lexicon+-- import NLP.GenI.LexicalSelection+-- import NLP.GenI.FeatureStructures++-- --------------------------------------------------------------------+-- ProgState+-- --------------------------------------------------------------------++-- | The program state consists of its configuration options and abstract,+--   cleaned up representations of all the data it's had to load into memory+--   (tree schemata files, lexicon files, etc).  The intention is for the+--   state to stay static until the next time something triggers some file+--   loading.+data ProgState = ProgState+    { pa       :: Params  -- ^ the current configuration+    , gr       :: Macros  -- ^ tree schemata+    , le       :: Lexicon -- ^ lexical entries+    , morphinf :: MorphInputFn -- ^ function to extract morphological+                               -- information from the semantics (you may+                               -- instead be looking for+                               -- 'NLP.GenI.Configuration.customMorph')+    , ranking  :: OtRanking -- ^ OT constraints    (optional)+    , traces   :: [Text]    -- ^ simplified traces (optional)+    }++type ProgStateRef = IORef ProgState++-- | The program state when you start GenI for the very first time+emptyProgState :: Params -> ProgState+emptyProgState args = ProgState+    { pa = args+    , gr = []+    , le = []+    , morphinf = const Nothing+    , traces = []+    , ranking = []+    }++-- --------------------------------------------------------------------+-- Interface+-- Loading and parsing+-- --------------------------------------------------------------------++-- | We have one master function that loads all the files GenI is expected to+--   use.  This just calls the sub-loaders below, some of which are exported+--   for use by the graphical interface.  The master function also makes sure+--   to complain intelligently if some of the required files are missing.+loadEverything :: ProgStateRef -> IO() +loadEverything pstRef =+  do pst <- readIORef pstRef+     --+     let config   = pa pst+         isMissing f = not $ hasFlagP f config+     -- grammar type+         isNotPreanchored = grammarType config /= PreAnchored+         isNotPrecompiled = grammarType config /= PreCompiled+         useTestSuite =  isMissing FromStdinFlg+                      && isMissing NoLoadTestSuiteFlg+     -- display +     let errormsg =+           concat $ intersperse ", " [ msg | (con, msg) <- errorlst, con ]+         errorlst =+              [ (isMissing RootFeatureFlg,+                "a root feature [empty feature is fine if you are not using polarity filtering]")+              , (isNotPrecompiled && isMissing MacrosFlg,+                "a tree file")+              , (isNotPreanchored && isMissing LexiconFlg,+                "a lexicon file")+              , (useTestSuite && isMissing TestSuiteFlg,+                "a test suite") ]+     unless (null errormsg) $ fail ("Please specify: " ++ errormsg)+     -- we only have to read in grammars from the simple format+     case grammarType config of +        PreAnchored -> return ()+        PreCompiled -> return ()+        _        -> loadGeniMacros pstRef >> return ()+     -- we don't have to read in the lexicon if it's already pre-anchored+     when isNotPreanchored $ loadLexicon pstRef >> return ()+     -- in any case, we have to...+     loadMorphInfo pstRef+     when useTestSuite $ loadTestSuite pstRef >> return ()+     -- the trace filter file+     loadTraces pstRef+     -- OT ranking+     loadRanking pstRef+++-- | The file loading functions all work the same way: we load the file,+--   and try to parse it.  If this doesn't work, we just fail in IO, and+--   GenI dies.  If we succeed, we update the program state passed in as+--   an IORef.+class Loadable x where+  lParse       :: FilePath -- ^ source (optional)+               -> String -> Either ParseError x+  lSet         :: x -> ProgState -> ProgState+  lSummarise   :: x -> String++-- | Note that here we assume the input consists of UTF-8 encoded file+lParseFromFile :: Loadable x => FilePath -> IO (Either ParseError x)+lParseFromFile f = lParse f `fmap` UTF8.readFile f++-- | Returns the input too (convenient for type checking)+lSetState :: Loadable x => ProgStateRef -> x -> IO x+lSetState pstRef x = modifyIORef pstRef (lSet x) >> return x++-- to be phased out+throwOnParseError :: String -> Either ParseError x -> IO x+throwOnParseError descr (Left err) = throwIO (BadInputException descr err)+throwOnParseError _ (Right p)  = return p++data BadInputException = BadInputException String ParseError+  deriving (Show, Typeable)++instance Exception BadInputException++data L a = Loadable a => L++-- | Load something, exiting GenI if we have not been given the+--   appropriate flag+loadOrDie :: forall f a . (Eq f, Typeable f, Loadable a)+          => L a+          -> (FilePath -> f) -- ^ flag+          -> String+          -> ProgStateRef+          -> IO a+loadOrDie L flg descr pstRef =+  withFlagOrDie flg pstRef descr $ \f -> do+   v <- verbosity pstRef+   x <- withLoadStatus v f descr lParseFromFile+     >>= throwOnParseError descr+     >>= lSetState pstRef+   return x++-- | Load something from a string rather than a file+loadFromString :: Loadable a => ProgStateRef+               -> String -- ^ description+               -> String -- ^ string to load+               -> IO a+loadFromString pstRef descr s =+  throwOnParseError descr (lParse "" s) >>= lSetState pstRef++instance Loadable Lexicon where+  lParse f = fmap toLexicon . runParser geniLexicon () f+    where+     fixEntry  = finaliseVars "" -- anonymise singletons for performance+               . sorter+     toLexicon = map fixEntry+     sorter l  = l { isemantics = (sortByAmbiguity . isemantics) l }+  lSet x p = p { le = x }+  lSummarise x = show (length x) ++ " lemmas"++instance Loadable Macros where+  lParse f = runParser geniMacros () f+  lSet x p = p { gr = x }+  lSummarise x = show (length x) ++ " schemata"++loadLexicon :: ProgStateRef -> IO Lexicon+loadLexicon = loadOrDie (L :: L Lexicon) LexiconFlg "lexicon"++-- | The macros are stored as a hashing function in the monad.+loadGeniMacros :: ProgStateRef -> IO Macros+loadGeniMacros pstRef =+  withFlagOrDie MacrosFlg pstRef descr $ \f -> do+     v <- verbosity pstRef+     withLoadStatus v f descr (parseFromFileMaybeBinary lParseFromFile)+     >>= throwOnParseError "tree schemata"+     >>= lSetState pstRef+  where+   descr = "trees"++-- | Load something, but only if we are configured to do so+loadOptional :: forall f a . (Eq f, Typeable f, Loadable a)+             => L a+             -> (FilePath -> f) -- ^ flag+             -> String+             -> ProgStateRef+             -> IO ()+loadOptional L flg descr pstRef =+  withFlagOrIgnore flg pstRef $ \f -> do+   v <- verbosity pstRef+   x <- withLoadStatus v f descr lParseFromFile+     >>= throwOnParseError descr+     >>= lSetState pstRef+   let _ = x :: a+   return () -- ignore++newtype MorphFnL = MorphFnL MorphInputFn++instance Loadable MorphFnL where+  lParse f = fmap (MorphFnL . readMorph) . runParser geniMorphInfo () f+  lSet (MorphFnL x) p = p { morphinf = x }+  lSummarise _ = "morphinfo"++newtype TracesL = TracesL [Text]++instance Loadable TracesL where+    lParse _ = Right . TracesL . T.lines . T.pack+    lSet (TracesL xs) p = p { traces = xs }+    lSummarise (TracesL xs) = show (length xs) ++ " traces"++instance Loadable OtRanking where+  lParse _ = resultToEither2 . decode+  lSet r p = p { ranking = r }+  lSummarise _ = "ranking"++loadMorphInfo :: ProgStateRef -> IO ()+loadMorphInfo = loadOptional (L :: L MorphFnL) MorphInfoFlg "morphological info"++loadTraces :: ProgStateRef -> IO ()+loadTraces = loadOptional (L :: L TracesL) TracesFlg "traces"++loadRanking :: ProgStateRef -> IO ()+loadRanking = loadOptional (L :: L OtRanking) RankingConstraintsFlg "OT constraints"++resultToEither2 :: Result a -> Either ParseError a+resultToEither2 r =+  case resultToEither r of+    Left e  -> runParser (fail e) () "" [] -- convoluted way to generate a Parsec error+    Right x -> Right x++-- Target semantics+--+-- Reading in the target semantics (or test suite) is a little more+-- complicated.  It follows the same general schema as above, except+-- that we parse the file twice: once for our internal representation,+-- and once to get a string representation of each test case.  The+-- string representation is for the graphical interface; it avoids us+-- figuring out how to pretty-print things because we can assume the+-- user will format it the way s/he wants.++newtype TestSuiteL = TestSuiteL [TestCase]++instance Loadable TestSuiteL where+ lParse f s =+   case runParser geniTestSuite () f s of+     Left e     -> Left e+     Right sem  -> case runParser geniTestSuiteString () f s of+        Left e      -> Left e+        Right mStrs -> Right (TestSuiteL (zipWith cleanup sem mStrs))+   where+    cleanup tc str =+        tc { tcSem = first3 sortSem (tcSem tc)+           , tcSemString = str }+ --+ lSet (TestSuiteL _) p = p+ lSummarise (TestSuiteL x) = show (length x) ++ " cases"++-- |+loadTestSuite :: ProgStateRef -> IO [TestCase]+loadTestSuite pstRef = do+  TestSuiteL xs <- loadOrDie (L :: L TestSuiteL) TestSuiteFlg "test suite" pstRef+  return xs++parseSemInput :: String -> Either ParseError SemInput+parseSemInput = fmap smooth . runParser geniSemanticInput () "semantics"+  where+    smooth (s,r,l) = (sortSem s, sort r, l)++-- Helpers for loading files++withFlag :: forall f a . (Eq f, Typeable f)+         => (FilePath -> f) -- ^ flag+         -> ProgStateRef+         -> IO a               -- ^ null action+         -> (FilePath -> IO a) -- ^ job+         -> IO a+withFlag flag pstRef z job =+ do config <- pa `fmap` readIORef pstRef+    case getFlagP flag config of+      Nothing -> z+      Just  x -> job x++withFlagOrIgnore :: forall f . (Eq f, Typeable f)+                 => (FilePath -> f) -- ^ flag+                 -> ProgStateRef+                 -> (FilePath -> IO ())+                 -> IO ()+withFlagOrIgnore flag pstRef = withFlag flag pstRef (return ())++withFlagOrDie :: forall f a . (Eq f, Typeable f)+              => (FilePath -> f) -- ^ flag+              -> ProgStateRef+              -> String+              -> (FilePath -> IO a)+              -> IO a+withFlagOrDie flag pstRef description =+    withFlag flag pstRef (fail msg)+  where+    msg = "Please specify a " ++ description ++ " file!"++withLoadStatus :: Loadable a+               => Bool                    -- ^ verbose+               -> FilePath             -- ^ file to load+               -> String               -- ^ description+               -> (FilePath -> IO (Either ParseError a)) -- ^ parsing cmd+               -> IO (Either ParseError a)+withLoadStatus False f _ p = p f+withLoadStatus True  f d p = do+  ePutStr $ unwords [ "Loading",  d, f ++ "... " ]+  eFlush+  mx <- p f+  ePutStrLn $ either (const "ERROR") (\x -> lSummarise x ++ " loaded") mx+  return mx++parseFromFileMaybeBinary :: Binary a+                         => (FilePath -> IO (Either ParseError a))+                         -> FilePath+                         -> IO (Either ParseError a)+parseFromFileMaybeBinary p f =+ if (".genib" `isSuffixOf` f)+    then Right `fmap` decodeFile f+    else p f++-- --------------------------------------------------------------------+-- Surface realisation - entry point+-- --------------------------------------------------------------------++-- | 'GeniResults' is the outcome of running GenI on a single input semantics.+--   Each distinct result is returned as a single 'GeniResult' (NB: a single+--   result may expand into multiple strings through morphological+--   post-processing),+data GeniResults = GeniResults+    { grResults        :: [GeniResult] -- ^ one per chart item+    , grGlobalWarnings :: [Text]       -- ^ usually from lexical selection+    , grStatistics     :: Statistics   -- ^ things like number of chart items+                                       --   to help study efficiency+    }++data GeniResult = GError   GeniError+                | GSuccess GeniSuccess+  deriving (Ord, Eq)++isSuccess :: GeniResult -> Bool+isSuccess (GSuccess _) = True+isSuccess (GError _)   = False++data GeniError = GeniError [Text]+  deriving (Ord, Eq)++data GeniSuccess = GeniSuccess+    { grLemmaSentence :: LemmaPlusSentence -- ^ “original” uninflected result +    , grRealisations  :: [Text]            -- ^ results after morphology+    , grResultType    :: ResultType+    , grWarnings      :: [Text]            -- ^ warnings “local” to this particular+                                           --   item, cf. 'grGlobalWarnings'+    , grDerivation    :: B.TagDerivation   -- ^ derivation tree behind the result+    , grOrigin        :: Integer           -- ^ normally a chart item id+    , grLexSelection  :: [GeniLexSel]      -- ^ the lexical selection behind+                                           --   this result (info only)+    , grRanking       :: Int               -- ^ see 'NLP.GenI.OptimalityTheory'+    , grViolations    :: [OtViolation]     -- ^ which OT constraints were violated+    } deriving (Ord, Eq)++data GeniLexSel = GeniLexSel+    { nlTree  :: Text+    , nlTrace :: [Text]+    } deriving (Ord, Eq)++data ResultType = CompleteResult | PartialResult deriving (Ord, Eq)++instance Pretty GeniError where+    pretty (GeniError xs) = T.intercalate "\n" $ map ("Error:" <+>) xs++-- | Entry point! (the most useful function to know here)+-- +--   * Initialises the realiser (lexical selection, among other things),+--+--   * Runs the builder (the surface realisation engine proper)+--+--   * Unpacks the builder results +--+--   * Finalises the results (morphological generation)+--+--   In addition to the results, this returns a generator state.  The latter is+--   is mostly useful for debugging via the graphical interface.+--   Note that we assumes that you have already loaded in your grammar and+--   parsed your input semantics.+runGeni :: ProgStateRef -> SemInput -> B.Builder st it Params -> IO (GeniResults,st)+runGeni pstRef semInput builder = do+     pst <- readIORef pstRef+     let config = pa pst+         run    = B.run builder+     -- step 1: lexical selection+     (initStuff, initWarns) <- initGeni pstRef semInput+     --force evaluation before measuring start time to avoid including grammar/lexicon parsing.+     start <- rnf initStuff `seq` getCPUTime+     -- step 2: chart generation+     let (finalSt, stats) = run initStuff config+     -- step 3: unpacking and+     -- step 4: post-processing+     results <- extractResults pstRef builder finalSt+     --force evaluation before measuring end time to account for all the work that should be done.+     end <- rnf results `seq` getCPUTime+     let elapsedTime = picosToMillis $! end - start+         diff = round (elapsedTime :: Double) :: Int+         stats2 = updateMetrics (incrIntMetric "gen_time"  (fromIntegral diff) ) stats+         gresults = GeniResults { grResults        = results+                                , grStatistics     = stats2+                                , grGlobalWarnings = map showWarnings (fromGeniWarnings initWarns)+                                }+     return (gresults, finalSt)+  where+    showWarnings = T.intercalate "\n" . showGeniWarning++-- | This is a helper to 'runGenI'. It's mainly useful if you are building+--   interactive GenI debugging tools.+--+--   Given a builder state,+--+--   * Unpacks the builder results+--+--   * Finalises the results (morphological generation)+extractResults :: ProgStateRef ->  B.Builder st it Params -> st -> IO [GeniResult]+extractResults pstRef builder finalSt = do+    config  <- pa <$> readIORef pstRef+    -- step 3: unpacking+    let uninflected = B.unpack builder finalSt+        (rawResults, resultTy) =+            if null uninflected && hasFlagP PartialFlg config+               then (B.partial builder finalSt, PartialResult)+               else (uninflected              , CompleteResult)+        status = B.finished builder finalSt+    -- step 4: post-processing+    finaliseResults pstRef (resultTy, status, rawResults)++-- --------------------------------------------------------------------+-- Surface realisation - sub steps+-- --------------------------------------------------------------------++-- | 'initGeni' performs lexical selection and strips the input semantics of+--   any morpohological literals+initGeni :: ProgStateRef -> SemInput -> IO (B.Input, GeniWarnings)+initGeni pstRef semInput_ = do+    pst <- readIORef pstRef+    let semInput = stripMorphStuff pst+                 . maybeRemoveConstraints pst+                 $ semInput_+    -- lexical selection+    selection <- runLexSelection pstRef semInput+    -- strip morphological predicates+    let initStuff = B.Input +          { B.inSemInput = semInput+          , B.inLex   = lsLexEntries selection+          , B.inCands = map (\c -> (c,-1)) (lsAnchored selection)+          }+    return (initStuff, lsWarnings selection)+  where+    stripMorphStuff pst = first3 (stripMorphSem (morphinf pst))+    -- disable constraints if the NoConstraintsFlg pessimisation is active+    maybeRemoveConstraints pst =+         if hasOpt NoConstraints (pa pst) then removeConstraints else id++-- | 'finaliseResults' does any post-processing steps that we want to integrate+--   into mainline GenI.  So far, this consists of morphological realisation and+--   OT ranking+finaliseResults :: ProgStateRef -> (ResultType, B.GenStatus, [B.Output]) -> IO [GeniResult]+finaliseResults pstRef (ty, status, os) = do+    pst <- readIORef pstRef+    -- morph TODO: make this a bit safer+    mss <- case getFlagP MorphCmdFlg (pa pst) of+             Nothing  -> let morph = fromMaybe (map sansMorph) (customMorph (pa pst))+                         in  return (morph sentences)+             Just cmd -> map snd `fmap` inflectSentencesUsingCmd cmd sentences+    -- OT ranking+    let unranked = zipWith (sansRanking pst) os mss+        rank = rankResults (getTraces pst) grDerivation (ranking pst)+        successes = map addRanking (rank unranked)+        failures  = case status of+                      B.Error str -> [GeniError [str]]+                      B.Finished  -> []+                      B.Active    -> []+    return (map GError failures ++ map GSuccess successes)+ where+  sentences = map snd3 os+  sansRanking pst (i,l,d) rs = GeniSuccess+               { grLemmaSentence = l+               , grRealisations = moRealisations rs+               , grWarnings     = moWarnings rs+               , grDerivation   = d+               , grLexSelection = map (\x -> GeniLexSel x (getTraces pst x)) (B.lexicalSelection d)+               , grRanking = -1+               , grViolations = []+               , grResultType = ty+               , grOrigin     = i+               }+  addRanking (i,res,vs) = res { grViolations = vs, grRanking = i }++-- --------------------------------------------------------------------+-- Displaying results+-- --------------------------------------------------------------------++-- | Show the sentences produced by the generator, in a relatively compact form+showRealisations :: [String] -> String+showRealisations [] = "(none)"+showRealisations xs = unlines . map sho . Map.toList . histogram $ xs+  where+   sho (x,1) = x+   sho (x,c) = x ++ " (" ++ show c ++ " instances)"++-- | No morphology! Pretend the lemma string is a sentence+lemmaSentenceString :: GeniSuccess -> Text+lemmaSentenceString = T.unwords . map lpLemma . grLemmaSentence++prettyResult :: ProgState -> GeniSuccess -> Text+prettyResult pst nr =+    T.intercalate "\n" . map showOne . grRealisations $ nr+ where+    showOne str = pretty theRanking <> ". " <> str <> "\n" <> violations+    violations  = prettyViolations tracesFn verbose (grViolations nr)+    theRanking  = grRanking nr+    verbose  = hasFlagP VerboseModeFlg (pa pst)+    tracesFn = getTraces pst++-- | 'getTraces' is most likely useful for grammars produced by a+--   metagrammar system.  Given a tree name, we retrieve the ``trace''+--   information from the grammar for all trees that have this name.  We+--   assume the tree name was constructed by GenI; see the source code for+--   details.+getTraces :: ProgState -> Text -> [Text]+getTraces pst tname =+  filt $ concat [ ptrace t | t <- gr pst, pidname t == readPidname tname ]+  where+   filt = case traces pst of+          []    -> id+          theTs -> filter (`elem` theTs)++-- | We assume the name was constructed by 'combineName'+readPidname :: Text -> Text+readPidname n =+    case T.splitOn ":" n of+        (_:_:p:_) -> p+        _         -> geniBug "NLP.GenI.readPidname or combineName are broken"++-- --------------------------------------------------------------------+-- Lexical selection+-- --------------------------------------------------------------------++-- | Runs the lexical selection (be it the standard GenI version or+--   a custom function supplied by a user) and runs the results+--   through the universal 'finaliseLexSelection'.+--+--   Also hunts for some warning conditions+runLexSelection :: ProgStateRef -> SemInput -> IO LexicalSelection+runLexSelection pstRef (tsem,_,litConstrs) = do+    pst <- readIORef pstRef+    let config   = pa pst+        verbose  = hasFlagP VerboseModeFlg config+    -- perform lexical selection+    selector  <- getLexicalSelector pstRef+    selection <- selector (gr pst) (le pst) tsem+    let lexCand   = lsLexEntries selection+        candFinal = finaliseLexSelection (morphinf pst) tsem litConstrs (lsAnchored selection)+    -- status+    when verbose $ T.hPutStrLn stderr . T.unlines $+        "Lexical items selected:"+        :  map (indent . showLexeme . fromFL . iword) lexCand+        ++ ["Trees anchored (family) :"]+        ++ map (indent . idname) candFinal+    -- warnings+    let semWarnings = case missingLiterals candFinal tsem of+                       [] -> []+                       xs -> [NoLexSelection xs]+    return $ selection { lsAnchored = candFinal+                       , lsWarnings = mkGeniWarnings semWarnings `mappend` lsWarnings selection+                       }+  where+    indent  x = ' ' `T.cons` x++-- | Grab the lexical selector from the config, or return the standard GenI+--   version if none is supplied+getLexicalSelector :: ProgStateRef -> IO LexicalSelector+getLexicalSelector pstRef = do+  config <- pa <$> readIORef pstRef+  case (customSelector config, grammarType config) of+    (Just s, _)            -> return s+    (Nothing, PreAnchored) -> mkPreAnchoredLexicalSelector pstRef+    (Nothing, _)           -> return defaultLexicalSelector++-- | @missingLiterals ts sem@ returns any literals in @sem@ that do not+--   appear in any of the @ts@ trees+missingLiterals :: [TagElem] -> [Literal GeniVal] -> [Literal GeniVal]+missingLiterals cands tsem =+   tsem \\ (nub $ concatMap tsemantics cands)++-- | Post-processes lexical selection results to things which+--   GenI considers applicable to all situations:+--+--   * attaches morphological information to trees+--+--   * throws out elementary trees that violate trace constraints+--     given by the user+--+--   * filters out any elementary tree whose semantics contains+--     things that are not in the input semantics+finaliseLexSelection :: MorphInputFn -> Sem -> [LitConstr] -> [TagElem] -> [TagElem]+finaliseLexSelection morph tsem litConstrs =+  setTidnums . considerCoherency . considerLc . considerMorph+ where+   -- attach any morphological information to the candidates+   considerMorph = attachMorph morph tsem+   -- filter out candidates which do not fulfill the trace constraints+   matchesLc t = all (`elem` myTrace) constrs+         where constrs = concat [ cs | (l,cs) <- litConstrs, l `elem` mySem ]+               mySem   = tsemantics t+               myTrace = ttrace t+   considerLc = filter matchesLc+   -- filter out candidates whose semantics has bonus stuff which does+   -- not occur in the input semantics+   considerCoherency = filter (all (`elem` tsem) . tsemantics)++-- --------------------------------------------------------------------+-- Pre-selection and pre-anchoring+-- --------------------------------------------------------------------++newtype PreAnchoredL = PreAnchoredL [TagElem]++instance Loadable PreAnchoredL where+  lParse f = fmap PreAnchoredL+           . runParser geniTagElems () f+  lSet _ p = p -- this does not update prog state at all+  lSummarise (PreAnchoredL xs) = show (length xs) ++ " trees"++readPreAnchored :: ProgStateRef -> IO [TagElem]+readPreAnchored pstRef = do+  PreAnchoredL xs <- loadOrDie (L :: L PreAnchoredL)+                        MacrosFlg "preanchored trees" pstRef+  return xs++mkPreAnchoredLexicalSelector :: ProgStateRef -> IO LexicalSelector+mkPreAnchoredLexicalSelector pstRef = do+  xs <- readPreAnchored pstRef+  return (\_ _ _ -> return (LexicalSelection xs [] mempty))++-- --------------------------------------------------------------------+-- Boring utility code+-- --------------------------------------------------------------------++verbosity :: ProgStateRef -> IO Bool+verbosity = fmap (hasFlagP VerboseModeFlg . pa)+          . readIORef++instance JSON GeniResult where+ readJSON j =+    case readJSON j of+      Ok s    -> Ok (GSuccess s)+      Error _ -> GError `fmap` readJSON j+ showJSON (GSuccess x) = showJSON x+ showJSON (GError   x) = showJSON x++instance JSON GeniSuccess where+ readJSON j = do+   jo <- fromJSObject `fmap` readJSON j+   let field x = maybe (fail $ "Could not find: " ++ x) readJSON+               $ lookup x jo+   GeniSuccess <$> field "raw"+               <*> field "realisations"+               <*> field "result-type"+               <*> field "warnings"+               <*> field "derivation"+               <*> field "chart-item"+               <*> field "lexical-selection"+               <*> field "ranking"+               <*> field "violations"+ showJSON nr =+     JSObject . toJSObject $ [ ("raw", showJSON $ grLemmaSentence nr)+                             , ("realisations", showJSONs $ grRealisations nr)+                             , ("derivation", showJSONs $ grDerivation nr)+                             , ("lexical-selection", showJSONs $ grLexSelection nr)+                             , ("ranking", showJSON $ grRanking nr)+                             , ("violations", showJSONs $ grViolations nr)+                             , ("result-type", showJSON $ grResultType nr)+                             , ("chart-item", showJSON $ grOrigin nr)+                             , ("warnings",   showJSONs $ grWarnings nr)+                             ]++instance JSON GeniError where+ readJSON j =+    do jo <- fromJSObject `fmap` readJSON j+       let field x = maybe (fail $ "Could not find: " ++ x) readJSON+                   $ lookup x jo+       GeniError  <$> field "errors"+ showJSON (GeniError xs) =+     JSObject . toJSObject $ [ ("errors", showJSON xs) ]++instance JSON ResultType where+  readJSON j =+    do js <- fromJSString `fmap` readJSON j+       case js of+         "partial"   -> return PartialResult+         "complete"  -> return CompleteResult+         ty          -> fail $ "unknown result type: " ++ ty+  showJSON CompleteResult = JSString $ toJSString "complete"+  showJSON PartialResult  = JSString $ toJSString "partial"++instance JSON GeniLexSel where+ readJSON j =+    do jo <- fromJSObject `fmap` readJSON j+       let field x = maybe (fail $ "Could not find: " ++ x) readJSON+                   $ lookup x jo+       GeniLexSel <$> field "lex-item"+                  <*> field "trace"+ showJSON x =+     JSObject . toJSObject $ [ ("lex-item", showJSON  $ nlTree x)+                             , ("trace",    showJSONs $ nlTrace x)+                             ]++-- Converts picoseconds to milliseconds.+picosToMillis :: Integer -> Double+picosToMillis t = realToFrac t / (10^(9 :: Int))++{-+data MNAME = MNAME deriving Typeable+logname :: String+logname = mkLogname MNAME+-}++{-!+deriving instance NFData GeniResult+deriving instance NFData GeniSuccess+deriving instance NFData GeniError+deriving instance NFData ResultType+deriving instance NFData GeniLexSel+!-}++-- GENERATED START++ +instance NFData GeniResult where+        rnf (GError x1) = rnf x1 `seq` ()+        rnf (GSuccess x1) = rnf x1 `seq` ()++ +instance NFData GeniSuccess where+        rnf (GeniSuccess x1 x2 x3 x4 x5 x6 x7 x8 x9)+          = rnf x1 `seq`+              rnf x2 `seq`+                rnf x3 `seq`+                  rnf x4 `seq`+                    rnf x5 `seq` rnf x6 `seq` rnf x7 `seq` rnf x8 `seq` rnf x9 `seq` ()++ +instance NFData GeniError where+        rnf (GeniError x1) = rnf x1 `seq` ()++ +instance NFData ResultType where+        rnf CompleteResult = ()+        rnf PartialResult = ()++ +instance NFData GeniLexSel where+        rnf (GeniLexSel x1 x2) = rnf x1 `seq` rnf x2 `seq` ()+-- GENERATED STOP
− src/NLP/GenI/Btypes.lhs
@@ -1,757 +0,0 @@-% GenI surface realiser-% Copyright (C) 2005 Carlos Areces and Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.--\chapter{Btypes}-\label{cha:Btypes}--This module provides basic datatypes like GNode, as well as operations-on trees, nodes and semantics.  Things here are meant to be relatively-low-level and primitive (well, with the exception of feature structure-unification, that is).--\ignore{-\begin{code}-{-# OPTIONS_GHC -fno-warn-orphans #-}-{-# LANGUAGE MultiParamTypeClasses, TypeSynonymInstances, FlexibleInstances, DeriveDataTypeable #-}-module NLP.GenI.Btypes(-   -- Datatypes-   GNode(..), GType(Subs, Foot, Lex, Other), NodeName,-   Ttree(..), MTtree, SemPols, TestCase(..),-   Ptype(Initial,Auxiliar,Unspecified),-   Pred, Flist, AvPair(..), GeniVal(..),-   Lexicon, ILexEntry(..), MorphLexEntry, Macros, Sem, LitConstr, SemInput, Subst,-   emptyLE, emptyGNode, emptyMacro,--   -- GNode stuff-   gCategory, showLexeme, lexemeAttributes, gnnameIs,--   -- Functions from Tree GNode-   plugTree, spliceTree,-   root, rootUpd, foot, setLexeme, setAnchor,--   -- Functions from Sem-   toKeys, subsumeSem, sortSem, showSem, showPred,-   emptyPred,--   -- Functions from Flist-   sortFlist, unify, unifyFeat, mergeSubst,-   showFlist, showPairs, showAv,--   -- Other functions-   replace, DescendGeniVal(..), replaceList,-   Collectable(..), Idable(..),-   alphaConvert, alphaConvertById,-   fromGConst, fromGVar,-   isConst, isVar, isAnon,--   -- Polarities--) where----- import Debug.Trace -- for test stuff-import Data.List-import Data.Maybe ( mapMaybe )-import Data.Function ( on )-import Data.Generics (Data)-import Data.Typeable (Typeable)-import qualified Data.Map as Map-import qualified Data.Set as Set-import Data.Tree--import Data.Generics.PlateDirect--import NLP.GenI.General(filterTree, listRepNode, snd3, geniBug)-import NLP.GenI.GeniVal----instance Show (IO()) where---  show _ = ""-\end{code}-}--% -----------------------------------------------------------------------\section{Grammar}-% ------------------------------------------------------------------------A grammar is composed of some unanchored trees (macros) and individual-lexical entries. The trees are grouped into families. Every lexical-entry is associated with a single family.  See section section-\ref{sec:combine_macros} for the process that combines lexical items-and trees into a set of anchored trees.--\begin{code}-type MTtree = Ttree GNode-type Macros = [MTtree]--data Ttree a = TT-  { params  :: [GeniVal]-  , pfamily :: String-  , pidname :: String-  , pinterface :: Flist-  , ptype :: Ptype-  , psemantics :: Maybe Sem-  , ptrace :: [String]-  , tree :: Tree a }-  deriving (Show, Data, Typeable)--data Ptype = Initial | Auxiliar | Unspecified-             deriving (Show, Eq, Data, Typeable)--instance Biplate (Ttree String) GeniVal where-  biplate (TT zps x1 x2 zint x3 zsem x4 x5) =-     plate TT ||* zps  |- x1 |- x2-              ||+ zint |- x3-              |+ zsem |- x4 |- x5--instance Biplate (Ttree GNode) GeniVal where-  biplate (TT zps x1 x2 zint x3 zsem x4 zt) =-     plate TT ||* zps  |- x1 |- x2-              ||+ zint |- x3-              |+ zsem |- x4-              |+ zt--instance DescendGeniVal (Ttree GNode) where-  descendGeniVal s mt =-    mt { params = descendGeniVal s (params mt)-       , tree   = descendGeniVal s (tree mt)-       , pinterface  = descendGeniVal s (pinterface mt)-       , psemantics = descendGeniVal s (psemantics mt) }--instance (Collectable a) => Collectable (Ttree a) where-  collect mt = (collect $ params mt) . (collect $ tree mt) .-               (collect $ psemantics mt) . (collect $ pinterface mt)---- | A null tree which you can use for various debugging or display purposes.-emptyMacro :: MTtree-emptyMacro = TT { params  = [],-                  pidname = "",-                  pfamily = "",-                  pinterface = [],-                  ptype = Unspecified,-                  psemantics = Nothing,-                  ptrace = [],-                  tree  = Node emptyGNode []-                 }-\end{code}--\paragraph{Lexical entries}--\begin{code}--- | A lexicon maps semantic predicates to lexical entries.-type Lexicon = Map.Map String [ILexEntry]-type SemPols  = [Int]-data ILexEntry = ILE-    { -- normally just a singleton, useful for merging synonyms-      iword       :: [String]-    , ifamname    :: String-    , iparams     :: [GeniVal]-    , iinterface  :: Flist-    , ifilters    :: Flist-    , iequations  :: Flist-    , iptype      :: Ptype-    , isemantics  :: Sem-    , isempols    :: [SemPols] }-  deriving (Show, Eq, Data, Typeable)--instance Biplate ILexEntry GeniVal where-  biplate (ILE x1 x2 zps zint zfilts zeq x3 zsem x4) =-    plate ILE |- x1 |- x2-              ||* zps-              ||+ zint-              ||+ zfilts-              ||+ zeq  |- x3-              ||+ zsem |- x4--instance DescendGeniVal ILexEntry where-  descendGeniVal s i =-    i { iinterface  = descendGeniVal s (iinterface i)-      , iequations  = descendGeniVal s (iequations i)-      , isemantics  = descendGeniVal s (isemantics i)-      , iparams = descendGeniVal s (iparams i) }--instance Collectable ILexEntry where-  collect l = (collect $ iinterface l) . (collect $ iparams l) .-              (collect $ ifilters l) . (collect $ iequations l) .-              (collect $ isemantics l)--emptyLE :: ILexEntry-emptyLE = ILE { iword = [],-                ifamname = "",-                iparams = [],-                iinterface   = [],-                ifilters = [],-                iptype = Unspecified,-                isemantics = [],-                iequations = [],-                isempols   = [] }-\end{code}--\begin{code}-type MorphLexEntry = (String,String,Flist)-\end{code}--% -----------------------------------------------------------------------\section{TAG nodes (GNode)}-% ------------------------------------------------------------------------\begin{code}--- | A single node of a TAG tree.-data GNode = GN{gnname :: NodeName,-                gup    :: Flist,      -- ^ top feature structure-                gdown  :: Flist,      -- ^ bottom feature structure-                ganchor  :: Bool,     -- ^ @False@ for na nodes-                glexeme  :: [String], -- ^ @[]@ for na nodes-                gtype    :: GType,-                gaconstr :: Bool,-                gorigin  :: String  -- ^ for TAG, this would be the elementary tree-                                    --   that this node originally came from-                }-           deriving (Eq, Data, Typeable)--instance Biplate GNode GeniVal where-  biplate (GN x1 zu zd x2 x3 x4 x5 x6) =-     plate GN |- x1-              ||+ zu-              ||+ zd |- x2 |- x3 |- x4 |- x5 |- x6--instance Biplate (Tree GNode) GeniVal where-  biplate (Node zn zkids) = plate Node |+ zn ||+ zkids---- Node type used during parsing of the grammar-data GType = Subs | Foot | Lex | Other-           deriving (Show, Eq, Data, Typeable)--type NodeName = String---- | A null 'GNode' which you can use for various debugging or display purposes.-emptyGNode :: GNode-emptyGNode = GN { gnname = "",-                  gup = [], gdown = [],-                  ganchor = False,-                  glexeme = [],-                  gtype = Other,-                  gaconstr = False,-                  gorigin = "" }--gnnameIs :: NodeName -> GNode -> Bool-gnnameIs n = (== n) . gnname-\end{code}--A TAG node may have a category.  In the core GenI algorithm, there is nothing-which distinguishes the category from any other attributes.  But for some-other uses, such as checking if it is a result or for display purposes, we-do treat this attribute differently.  We take here the convention that the-category of a node is associated to the attribute ``cat''.-\begin{code}--- | Return the value of the "cat" attribute, if available-gCategory :: Flist -> Maybe GeniVal-gCategory top =-  case [ v | AvPair "cat" v <- top ] of-  []  -> Nothing-  [c] -> Just c-  _   -> geniBug $ "Impossible case: node with more than one category"-\end{code}--A TAG node might also have a lexeme.  If we are lucky, this is explicitly-set in the glexeme field of the node.  Otherwise, we try to guess it from-a list of distinguished attributes (in order of preference).-\begin{code}--- | Attributes recognised as lexemes, in order of preference-lexemeAttributes :: [String]-lexemeAttributes = [ "lex", "phon", "cat" ]-\end{code}--\paragraph{show (GNode)} the default show for GNode tries to-be very compact; it only shows the value for cat attribute-and any flags which are marked on that node.--\begin{code}-instance Show GNode where-  show gn =-    let cat_ = case gCategory.gup $ gn of-               Nothing -> []-               Just c  -> show c-        lex_ = showLexeme $ glexeme gn-        ---        stub = concat $ intersperse ":" $ filter (not.null) [ cat_, lex_ ]-        extra = case (gtype gn) of-                   Subs -> " !"-                   Foot -> " *"-                   _    -> if (gaconstr gn)  then " #"   else ""-    in stub ++ extra---- FIXME: will have to think of nicer way - one which involves--- unpacking the trees :-(-showLexeme :: [String] -> String-showLexeme []   = ""-showLexeme [l]  = l-showLexeme xs   = concat $ intersperse "|" xs-\end{code}--A Replacement on a GNode consists of replacements on its top and bottom-feature structures--\begin{code}-instance DescendGeniVal GNode where-  descendGeniVal s gn =-    gn { gup = descendGeniVal s (gup gn)-       , gdown = descendGeniVal s (gdown gn) }-\end{code}--% -----------------------------------------------------------------------\section{Tree manipulation}-% ------------------------------------------------------------------------\begin{code}-root :: Tree a -> a-root (Node a _) = a--rootUpd :: Tree a -> a -> Tree a-rootUpd (Node _ l) b = (Node b l)--foot :: Tree GNode -> GNode-foot t = case filterTree (\n -> gtype n == Foot) t of-         [x] -> x-         _   -> geniBug $ "foot returned weird result"-\end{code}--\begin{code}--- | Given a lexical item @s@ and a Tree GNode t, returns the tree t'---   where l has been assigned to the anchor node in t'-setAnchor :: [String] -> Tree GNode -> Tree GNode-setAnchor s t =-  let filt (Node a []) = (gtype a == Lex && ganchor a)-      filt _ = False-  in case listRepNode (setLexeme s) filt [t] of-     ([r],True) -> r-     _ -> geniBug $ "setLexeme " ++ show s ++ " returned weird result"---- | Given a lexical item @l@ and a tree node @n@ (actually a subtree---   with no children), return the same node with the lexical item as---   its unique child.  The idea is that it converts terminal lexeme nodes---   into preterminal nodes where the actual terminal is the given lexical---   item-setLexeme :: [String] -> Tree GNode -> Tree GNode-setLexeme l (Node a []) = Node a [ Node subanc [] ]-  where subanc = emptyGNode { gnname = '_' : ((gnname a) ++ ('.' : (concat l)))-                            , gaconstr = True-                            , glexeme = l}-setLexeme _ _ = geniBug "impossible case in setLexeme - subtree with kids"-\end{code}--\subsection{Substitution and Adjunction}--This module handles just the tree-cutting aspects of TAG substitution and-adjunction.  We do substitution with a very general \fnreflite{plugTree}-function, whose only job is to plug two trees together at a specified node.-Note that this function is also used to implement adjunction.--\begin{code}--- | Plug the first tree into the second tree at the specified node.---   Anything below the second node is silently discarded.---   We assume the trees are pluggable; it is treated as a bug if---   they are not!-plugTree :: Tree NodeName -> NodeName -> Tree NodeName -> Tree NodeName-plugTree male n female =-  case listRepNode (const male) (nmatch n) [female] of-  ([r], True) -> r-  _           -> geniBug $ "unexpected plug failure at node " ++ n---- | Given two trees 'auxt' and 't', splice the tree 'auxt' into---   't' via the TAG adjunction rule.-spliceTree :: NodeName      -- ^ foot node of the aux tree-           -> Tree NodeName -- ^ aux tree-           -> NodeName      -- ^ place to adjoin in target tree-           -> Tree NodeName -- ^ target tree-           -> Tree NodeName-spliceTree f auxT n targetT =-  case findSubTree n targetT of -- excise the subtree at n-  Nothing -> geniBug $ "Unexpected adjunction failure. " ++-                       "Could not find node " ++ n ++ " of target tree."-  Just eT -> -- plug the excised bit into the aux-             let auxPlus = plugTree eT f auxT-             -- plug the augmented aux at n-             in  plugTree auxPlus n targetT--nmatch :: NodeName -> Tree NodeName -> Bool-nmatch n (Node a _) = a == n--findSubTree :: NodeName -> Tree NodeName -> Maybe (Tree NodeName)-findSubTree n n2@(Node x ks)-  | x == n    = Just n2-  | otherwise = case mapMaybe (findSubTree n) ks of-                []    -> Nothing-                (h:_) -> Just h-\end{code}--% -----------------------------------------------------------------------\section{Features and variables}-% ------------------------------------------------------------------------\begin{code}-type Flist   = [AvPair]-data AvPair  = AvPair { avAtt :: String-                      , avVal ::  GeniVal }-  deriving (Ord, Eq, Data, Typeable)--instance Biplate AvPair GeniVal where-  biplate (AvPair a v) = plate AvPair |- a |* v-\end{code}--\subsection{Collectable}--A Collectable is something which can return its variables as a set.-By variables, what I most had in mind was the GVar values in a-GeniVal.  This notion is probably not very useful outside the context of-alpha-conversion task, but it seems general enough that I'll keep it-around for a good bit, until either some use for it creeps up, or I find-a more general notion that I can transform this into.--\begin{code}-class Collectable a where-  collect :: a -> Set.Set String -> Set.Set String--instance Collectable a => Collectable (Maybe a) where-  collect Nothing  s = s-  collect (Just x) s = collect x s--instance (Collectable a => Collectable [a]) where-  collect l s = foldr collect s l--instance (Collectable a => Collectable (Tree a)) where-  collect = collect.flatten---- Pred is what I had in mind here-instance ((Collectable a, Collectable b, Collectable c)-           => Collectable (a,b,c)) where-  collect (a,b,c) = collect a . collect b . collect c--instance Collectable GeniVal where-  collect (GVar v) s = Set.insert v s-  collect _ s = s--instance Collectable AvPair where-  collect (AvPair _ b) = collect b--instance Collectable GNode where-  collect n = (collect $ gdown n) . (collect $ gup n)-\end{code}--\subsection{DescendGeniVal}-\label{sec:replacable}-\label{sec:replacements}--The idea of replacing one variable value with another is something that-appears all over the place in GenI.  So we try to smooth out its use by-making a type class out of it.--\begin{code}--\end{code}--Substitution on list consists of performing substitution on-each item.  Each item, is independent of the other,-of course.--\begin{code}-instance DescendGeniVal a => DescendGeniVal (Map.Map k a) where-  descendGeniVal s = {-# SCC "descendGeniVal" #-} Map.map (descendGeniVal s)--instance DescendGeniVal AvPair where-  descendGeniVal s (AvPair a v) = {-# SCC "descendGeniVal" #-} AvPair a (descendGeniVal s v)--instance DescendGeniVal a => DescendGeniVal (String, a) where-  descendGeniVal s (n,v) = {-# SCC "descendGeniVal" #-} (n,descendGeniVal s v)--instance DescendGeniVal ([String], Flist) where-  descendGeniVal s (a,v) = {-# SCC "descendGeniVal" #-} (a, descendGeniVal s v)-\end{code}--\subsection{Idable}--\begin{code}--- | An Idable is something that can be mapped to a unique id.---   You might consider using this to implement Ord, but I won't.---   Note that the only use I have for this so far (20 dec 2005)---  is in alpha-conversion.-class Idable a where-  idOf :: a -> Integer-\end{code}--\subsection{Other feature and variable stuff}--Our approach to $\alpha$-conversion works by appending a unique suffix-to all variables in an object.  See section \ref{sec:fs_unification} for-why we want this.--\begin{code}-alphaConvertById :: (Collectable a, DescendGeniVal a, Idable a) => a -> a-alphaConvertById x = {-# SCC "alphaConvertById" #-}-  alphaConvert ('-' : (show . idOf $ x)) x--alphaConvert :: (Collectable a, DescendGeniVal a) => String -> a -> a-alphaConvert suffix x = {-# SCC "alphaConvert" #-}-  let vars   = Set.elems $ collect x Set.empty-      convert v = GVar (v ++ suffix)-      subst = Map.fromList $ map (\v -> (v, convert v)) vars-  in replace subst x-\end{code}--\begin{code}--- | Sort an Flist according with its attributes-sortFlist :: Flist -> Flist-sortFlist = sortBy (compare `on` avAtt)--showFlist :: Flist -> String-showFlist f = "[" ++ showPairs f ++ "]"--showPairs :: Flist -> String-showPairs = unwords . map showAv--showAv :: AvPair -> String-showAv (AvPair y z) = y ++ ":" ++ show z--instance Show AvPair where-  show = showAv-\end{code}--% -----------------------------------------------------------------------\section{Semantics}-\label{btypes_semantics}-% ------------------------------------------------------------------------\begin{code}--- handle, predicate, parameters-type Pred = (GeniVal, GeniVal, [GeniVal])-type Sem = [Pred]-type LitConstr = (Pred, [String])-type SemInput  = (Sem,Flist,[LitConstr])--instance Biplate Pred GeniVal where-  biplate (g1, g2, g3) = plate (,,) |* g1 |* g2 ||* g3--instance Biplate (Maybe Sem) GeniVal where-  biplate (Just s) = plate Just ||+ s-  biplate Nothing  = plate Nothing--data TestCase = TestCase-       { tcName :: String-       , tcSemString :: String -- ^ for gui-       , tcSem  :: SemInput-       , tcExpected :: [String] -- ^ expected results (for testing)-       , tcOutputs :: [(String, Map.Map (String,String) [String])]-       -- ^ results we actually got, and their traces (for testing)-       } deriving Show--emptyPred :: Pred-emptyPred = (GAnon,GAnon,[])-\end{code}--A replacement on a predicate is just a replacement on its parameters--\begin{code}-instance DescendGeniVal Pred where-  descendGeniVal s (h, n, lp) = (descendGeniVal s h, descendGeniVal s n, descendGeniVal s lp)-\end{code}--\begin{code}-showSem :: Sem -> String-showSem l =-    "[" ++ (unwords $ map showPred l) ++ "]"--showPred :: Pred -> String-showPred (h, p, l) = showh ++ show p ++ "(" ++ unwords (map show l) ++ ")"-  where-    hideh (GConst [x]) = "genihandle" `isPrefixOf` x-    hideh _ = False-    ---    showh = if (hideh h) then "" else (show h) ++ ":"-\end{code}--\begin{code}--- | Given a Semantics, return the string with the proper keys---   (propsymbol+arity) to access the agenda-toKeys :: Sem -> [String]-toKeys l = map (\(_,prop,par) -> show prop ++ (show $ length par)) l-\end{code}--\subsection{Semantic subsumption}-\label{fn:subsumeSem}--FIXME: comment fix--Given tsem the input semantics, and lsem the semantics of a potential-lexical candidate, returns a list of possible ways that the lexical-semantics could subsume the input semantics.  We return a pair with-the semantics that would result from unification\footnote{We need to-do this because there may be anonymous variables}, and the-substitutions that need to be propagated throughout the rest of the-lexical item later on.--Note: we return more than one possible substitution because s could be-different subsets of ts.  Consider, for example, \semexpr{love(j,m),-  name(j,john), name(m,mary)} and the candidate \semexpr{name(X,Y)}.--TODO WE ASSUME BOTH SEMANTICS ARE ORDERED and that the input semantics is-non-empty.--\begin{code}-subsumeSem :: Sem -> Sem -> [(Sem,Subst)]-subsumeSem tsem lsem =-  subsumeSemHelper ([],Map.empty) (reverse tsem) (reverse lsem)-\end{code}--This is tricky because each substep returns multiple results.  We solicit-the help of accumulators to keep things from getting confused.--\begin{code}-subsumeSemHelper :: (Sem,Subst) -> Sem -> Sem -> [(Sem,Subst)]-subsumeSemHelper _ [] _  =-  error "input semantics is non-empty in subsumeSemHelper"-subsumeSemHelper acc _ []      = [acc]-subsumeSemHelper acc tsem (hd:tl) =-  let (accSem,accSub) = acc-      -- does the literal hd subsume the input semantics?-      pRes = subsumePred tsem hd-      -- toPred reconstructs the literal hd with new parameters p.-      -- The head of the list is taken to be the handle.-      toPred p = (head p, snd3 hd, tail p)-      -- next adds a result from predication subsumption to-      -- the accumulators and goes to the next recursive step-      next (p,s) = subsumeSemHelper acc2 tsem2 tl2-         where tl2   = replace s tl-               tsem2 = replace s tsem-               acc2  = (toPred p : accSem, mergeSubst accSub s)-  in concatMap next pRes-\end{code}--\fnlabel{subsumePred}-The first Sem s1 and second Sem s2 are the same when we start we circle on s2-looking for a match for Pred, and meanwhile we apply the partical substitutions-to s1.  Note: we treat the handle as if it were a parameter.--\begin{code}-subsumePred :: Sem -> Pred -> [([GeniVal],Subst)]-subsumePred [] _ = []-subsumePred ((h1, p1, la1):l) (pred2@(h2,p2,la2)) =-    -- if we found the proper predicate-    if ((p1 == p2) && (length la1 == length la2))-    then let mrs  = unify (h1:la1) (h2:la2)-             next = subsumePred l pred2-         in maybe next (:next) mrs-    else if (p1 < p2) -- note that the semantics have to be reversed!-         then []-         else subsumePred l pred2-\end{code}--\subsection{Other semantic stuff}--\begin{code}--- | Sort semantics first according to its predicate, and then to its handles.-sortSem :: Sem -> Sem-sortSem = sortBy (\(h1,p1,a1) (h2,p2,a2) -> compare (p1, h1:a1) (p2, h2:a2))-\end{code}--% ---------------------------------------------------------------------\subsection{Feature structure unification}-\label{sec:fs_unification}-% ----------------------------------------------------------------------Feature structure unification takes two feature lists as input.  If it-fails, it returns Nothing.  Otherwise, it returns a tuple with:--\begin{enumerate}-\item a unified feature structure list-\item a list of variable replacements that will need to be propagated-      across other feature structures with the same variables-\end{enumerate}--Unification fails if, at any point during the unification process, the-two lists have different constant values for the same attribute.-For example, unification fails on the following inputs because they have-different values for the \textit{number} attribute:--\begin{quotation}-\fs{\it cat:np\\ \it number:3\\}-\fs{\it cat:np\\ \it number:2\\}-\end{quotation}--Note that the following input should also fail as a result on the-coreference on \textit{?X}.--\begin{quotation}-\fs{\it cat:np\\ \it one: 1\\  \it two:2\\}-\fs{\it cat:np\\ \it one: ?X\\ \it two:?X\\}-\end{quotation}--On the other hand, any other pair of feature lists should unify-succesfully, even those that do not share the same attributes.-Below are some examples of successful unifications:--\begin{quotation}-\fs{\it cat:np\\ \it one: 1\\  \it two:2\\}-\fs{\it cat:np\\ \it one: ?X\\ \it two:?Y\\}-$\rightarrow$-\fs{\it cat:np\\ \it one: 1\\ \it two:2\\},-\end{quotation}--\begin{quotation}-\fs{\it cat:np\\ \it number:3\\}-\fs{\it cat:np\\ \it case:nom\\}-$\rightarrow$-\fs{\it cat:np\\ \it case:nom\\ \it number:3\\},-\end{quotation}--\begin{code}--- | 'unifyFeat' performs feature structure unification, under the---   these assumptions about the input:------    * Features are ordered------    * The Flists do not share variables (renaming has already---      been done.------   The features are allowed to have different sets of attributes,---   beacuse we use 'alignFeat' to realign them.-unifyFeat :: Monad m => Flist -> Flist -> m (Flist, Subst)-unifyFeat f1 f2 =-  {-# SCC "unification" #-}-  let (att, val1, val2) = unzip3 $ alignFeat f1 f2-  in att `seq`-     do (res, subst) <- unify val1 val2-        return (zipWith AvPair att res, subst)---- | 'alignFeat' is a pre-procesing step used to ensure that feature structures---   have the same set of keys.  If a key is missing in one, we copy it to the---   other with an anonymous value.------   The two feature structures must be sorted for this to work-alignFeat :: Flist -> Flist -> [(String,GeniVal,GeniVal)]-alignFeat f1 f2 = alignFeatH f1 f2 []--alignFeatH :: Flist -> Flist -> [(String,GeniVal,GeniVal)] -> [(String,GeniVal,GeniVal)]-alignFeatH [] [] acc = reverse acc-alignFeatH [] (AvPair f v :x) acc = alignFeatH [] x ((f,GAnon,v) : acc)-alignFeatH x [] acc = alignFeatH [] x acc-alignFeatH fs1@(AvPair f1 v1:l1) fs2@(AvPair f2 v2:l2) acc =-   case compare f1 f2 of-     EQ -> alignFeatH l1 l2  ((f1, v1, v2) : acc)-     LT -> alignFeatH l1 fs2 ((f1, v1, GAnon) : acc)-     GT -> alignFeatH fs1 l2 ((f2, GAnon, v2) : acc)-\end{code}--
− src/NLP/GenI/BtypesBinary.hs
@@ -1,59 +0,0 @@-{-# OPTIONS -fno-warn-orphans #-}-module NLP.GenI.BtypesBinary where--import Data.Binary-import NLP.GenI.Btypes---- auto-generated by the Data.Binary BinaryDerive tool-instance Binary NLP.GenI.Btypes.Ptype where-  put Initial = putWord8 0-  put Auxiliar = putWord8 1-  put Unspecified = putWord8 2-  get = do-    tag_ <- getWord8-    case tag_ of-      0 -> return Initial-      1 -> return Auxiliar-      2 -> return Unspecified-      _ -> fail "no parse"-instance Binary NLP.GenI.Btypes.GeniVal where-  put (GConst a) = putWord8 0 >> put a-  put (GVar a) = putWord8 1 >> put a-  put GAnon = putWord8 2-  get = do-    tag_ <- getWord8-    case tag_ of-      0 -> get >>= \a -> return (GConst a)-      1 -> get >>= \a -> return (GVar a)-      2 -> return GAnon-      _ -> fail "no parse"-instance Binary NLP.GenI.Btypes.GNode where-  put (GN a b c d e f g h) = put a >> put b >> put c >> put d >> put e >> put f >> put g >> put h-  get = get >>= \a -> get >>= \b -> get >>= \c -> get >>= \d -> get >>= \e -> get >>= \f -> get >>= \g -> get >>= \h -> return (GN a b c d e f g h)--instance Binary NLP.GenI.Btypes.GType where-  put Subs = putWord8 0-  put Foot = putWord8 1-  put Lex = putWord8 2-  put Other = putWord8 3-  get = do-    tag_ <- getWord8-    case tag_ of-      0 -> return Subs-      1 -> return Foot-      2 -> return Lex-      3 -> return Other-      _ -> fail "no parse"-instance (Binary a) => Binary (NLP.GenI.Btypes.Ttree a) where-  put (TT a b c d e f g h) = put a >> put b >> put c >> put d >> put e >> put f >> put g >> put h-  get = get >>= \a -> get >>= \b -> get >>= \c -> get >>= \d -> get >>= \e -> get >>= \f -> get >>= \g -> get >>= \h -> return (TT a b c d e f g h)---instance Binary NLP.GenI.Btypes.AvPair where-  put (AvPair a b)  = put a >> put b-  get = get >>= \a -> get >>= \b -> return (AvPair a b)--instance Binary NLP.GenI.Btypes.ILexEntry where-  put (ILE a b c d e f g h i) = put a >> put b >> put c >> put d >> put e >> put f >> put g >> put h >> put i-  get = get >>= \a -> get >>= \b -> get >>= \c -> get >>= \d -> get >>= \e -> get >>= \f -> get >>= \g -> get >>= \h -> get >>= \i -> return (ILE a b c d e f g h i)-
+ src/NLP/GenI/Builder.hs view
@@ -0,0 +1,404 @@+-- GenI surface realiser+-- Copyright (C) 2005 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.++{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE DeriveDataTypeable #-}++{-|+The heavy lifting of GenI, the whole chart/agenda mechanism, can be+implemented in many ways.  To make it easier to write different+algorithms for GenI and compare them, we provide a single interface+for what we call Builders.++This interface is then used called by the Geni module and by the+graphical interface.  Note that each builder has its own graphical+interface and that we do a similar thing in the graphical interface+code to make it possible to use these GUIs.+-}++module NLP.GenI.Builder (+ TagDerivation, Builder(..), GenStatus(..),+ lexicalSelection, FilterStatus(..),incrCounter, num_iterations,+ (>-->),+ num_comparisons, chart_size,+ SemBitMap, defineSemanticBits, semToBitVector, bitVectorToSem, DispatchFilter, condFilter,+ defaultStepAll,+ BuilderState, UninflectedDisjunction(..), Input(..), unlessEmptySem,+ initStats, Output, SentenceAut, run, queryCounter, defaultMetricNames, preInit+)+where++import Control.Monad.State.Strict+import Data.Bits ( (.&.), (.|.), bit )+import Data.List ( delete, sort, nub )+import Data.Maybe ( mapMaybe, fromMaybe, maybeToList )+import Data.Tree ( flatten )+import Prelude hiding ( init )+import Data.Text ( Text )+import qualified Data.Map as Map+import qualified Data.Text as T++import Control.DeepSeq++import Data.Generics ( Data )+import Data.Typeable ( Typeable )++import NLP.GenI.Automaton (NFA, automatonPaths, automatonPathSets, numStates, numTransitions)+import NLP.GenI.Configuration+  ( getListFlagP, getFlagP, modifyFlagP, Params,+    DetectPolaritiesFlg(..),+    MetricsFlg(..),+    RootFeatureFlg(..),+    Optimisation(..), hasOpt,+  )+import NLP.GenI.FeatureStructure ( Flist, sortFlist, mkFeatStruct )+import NLP.GenI.General ( BitVector, snd3, thd3, geniBug )+import NLP.GenI.GeniVal ( GeniVal, DescendGeniVal(..), Collectable(collect), finaliseVarsById )+import NLP.GenI.Lexicon ( LexEntry )+import NLP.GenI.Morphology.Types+import NLP.GenI.Polarity  (PolResult(..), buildAutomaton, detectPolPaths)+import NLP.GenI.Pretty+import NLP.GenI.Semantics ( SemInput, Sem, Literal )+import NLP.GenI.Statistics (Statistics, incrIntMetric,+                   Metric(IntMetric), updateMetrics,+                   queryMetrics, queryIntMetric,+                   addMetric, emptyStats,+                   )+import NLP.GenI.Tag+    ( TagElem(idname,tsemantics,ttree), setTidnums+    , TagDerivation, dsChild, dsParent+    )+import NLP.GenI.TreeSchema ( GNode(..), GType(Subs, Foot) )++data GenStatus = Finished+               | Active+               | Error Text++data Builder st it pa = Builder+  { init     :: Input -> pa -> (st, Statistics)+             -- ^ initialise the machine from the semantics and lexical selection +  , step     :: BuilderState st () -- ^ run a realisation step+  , stepAll  :: BuilderState st () -- ^ run all realisations steps until completion+  --+  , finished :: st -> GenStatus    -- ^ determine if realisation is finished+  , unpack   :: st -> [Output]     -- ^ unpack chart results into a list of sentences+  , partial  :: st -> [Output]+  }++type Output = (Integer, LemmaPlusSentence, TagDerivation)++-- | To simplify interaction with the backend, we provide a single data+--   structure which represents all the inputs a backend could take.++data Input = +  Input { inSemInput :: SemInput+        , inLex      :: [LexEntry] -- ^ for the debugger+        , inCands    :: [(TagElem, BitVector)]   -- ^ tag tree+        }++-- Uninflected words and sentences++-- | A SentenceAut represents a set of sentences in the form of an automaton.+--   The labels of the automaton are the words of the sentence.  But note! +--   “word“ in the sentence is in fact a tuple (lemma, inflectional feature+--   structures).  Normally, the states are defined as integers, with the+--   only requirement being that each one, naturally enough, is unique.+type SentenceAut            = NFA Int LemmaPlus++data UninflectedDisjunction = UninflectedDisjunction [Text] (Flist GeniVal) deriving (Data, Typeable)++instance DescendGeniVal UninflectedDisjunction where+  descendGeniVal s (UninflectedDisjunction a v) = {-# SCC "descendGeniVal" #-} UninflectedDisjunction a (descendGeniVal s v)++instance Collectable UninflectedDisjunction where+  collect (UninflectedDisjunction _ b) = collect b++-- BuilderState++-- To cleanly seperate the tracking of statistics from the core functionality of a+-- builder, we use a State transformer to thread a Statistics state monad inside of+-- our main monad.+type BuilderState s a = StateT s (State Statistics) a++-- ----------------------------------------------------------------------+-- Helper functions for Builders+-- ----------------------------------------------------------------------++-- Initialisation+--+-- There's a few things that need to be run before even initialising the builder.+-- One of these is running some of the optimisations (namely the polarity stuff),+-- which is made complicated by the fact that they are optional.  Another of these+-- to assign each of the trees with a unique ID.  Note that this has to be done+-- after the polarity optimisation because this optimisation may introduce new+-- items into the lexical selection.  Finally, we must also make sure we perform+-- alpha conversion so that unification does not do the wrong thing when two trees+-- have the same variables.++preInit :: Input -> Params -> (Input, PolResult)+preInit input config =+ let (cand,_) = unzip $ inCands input+     seminput = inSemInput input+     --+     extraPol = Map.empty+     polsToDetect = fromMaybe (error "there should be a default for --detect-pols")+                  $ getFlagP DetectPolaritiesFlg config+     rootFeat = mkFeatStruct $ getListFlagP RootFeatureFlg config+     -- do any optimisations+     isPol = hasOpt Polarised config+     -- polarity optimisation (if enabled)+     autstuff = buildAutomaton polsToDetect rootFeat extraPol seminput cand+     autpaths = map concat . automatonPathSets . prFinal $ autstuff+     combosPol = if isPol then autpaths else [considerHasSem cand]+     considerHasSem = filter (not . null . tsemantics)+     -- polarity automaton construction uses the zero literal semantic+     -- items, but it may be safer to filter them out now if we are not+     -- using it+     -- chart sharing optimisation+     (cands2, pathIds) = unzip $ detectPolPaths combosPol+     --+     fixate ts ps = zip (map finaliseVarsById $ setTidnums ts) ps+     input2 = input { inCands    = fixate cands2 pathIds+                    , inSemInput = (prSem autstuff, snd3 seminput, thd3 seminput) }+     -- note: autstuff is only useful for the graphical debugger+  in (input2, autstuff)++-- | Equivalent to 'id' unless the input contains an empty or uninstatiated+--   semantics+unlessEmptySem :: Input -> Params -> a -> a+unlessEmptySem input _+    | null semanticsErr = id+    | otherwise         = error semanticsErr+  where+    (cands,_) = unzip $ inCands input+    nullSemCands   = [ idname t | t <- cands, (null.tsemantics) t ]+    unInstSemCands = [ idname t | t <- cands, not $ Map.null $ collect (tsemantics t) Map.empty ]+    nullSemErr     =+        "The following trees have a null semantics: " +++         T.unpack (T.unwords nullSemCands)+    unInstSemErr   =+        "The following trees have an uninstantiated semantics: " +++        T.unpack (T.unwords unInstSemCands)+    semanticsErr =+        (if null nullSemCands   then "" else nullSemErr ++ "\n") +++        (if null unInstSemCands then "" else unInstSemErr)++-- ----------------------------------------------------------------------+-- Running a surface realiser+-- ----------------------------------------------------------------------++-- | Performs surface realisation from an input semantics and a lexical selection.+--+--   Statistics tracked+--+--    * pol_used_bundles - number of bundled paths through the polarity automaton.+--                         see 'NLP.GenI.Automaton.automatonPathSets'+--+--    * pol_used_paths - number of paths through the final automaton+--+--    * pol_seed_paths - number of paths through the seed automaton (i.e. with no polarities).+--                       This is normally just 1, unless you have multi-literal semantics+--+--    * pol_total_states - combined number of states in the all the polarity automata+--+--    * pol_total_tras - combined number of transitions in all polarity automata+--+--    * pol_max_states - number of states in the polarity automaton with the most states+--+--    * pol_total_tras - number of transitions in the polarity automata with the most transitions+--+--    * sem_literals    - number of literals in the input semantics+--+--    * lex_trees       - total number of lexically selected trees++--    * lex_foot_nodes  - total number of nodes of any sort in lexically selected trees+--+--    * lex_subst_nodes - total number of sustitution nodes in lexically selected trees+--+--    * lex_foot_nodes  - total number of foot nodes in lexically selected trees+--+--    * plex_...        - same as the lex_ equivalent, but after polarity filtering+run :: Builder st it Params -> Input -> Params -> (st, Statistics)+run builder input config_ =+  let -- 0 normalise the config+      config = modifyFlagP RootFeatureFlg sortFlist config_+      -- 1 run the setup stuff+      (input2, autstuff) = preInit input config+      auts = map snd3 (prIntermediate autstuff)+      -- 2 call the init stuff+      (iSt, iStats) = init builder input2 config+      -- 2b extra statistics+      autpaths = map concat . automatonPathSets . prFinal $ autstuff+      countsFor ts = (length ts, length nodes, length sn, length an)+        where nodes = concatMap (flatten.ttree) ts+              sn = [ n | n <- nodes, gtype n == Subs  ]+              an = [ n | n <- nodes, gtype n == Foot  ]+      (tsem,_,_) = inSemInput input+      cands = nub . map fst $ inCands input+      cands2 = nub . concatMap concat . automatonPathSets . prFinal $ autstuff+      countUp = do incrCounter "sem_literals"  $ length tsem+                   --+                   incrCounter "lex_subst_nodes" snl+                   incrCounter "lex_foot_nodes"  anl+                   incrCounter "lex_nodes"        nl+                   incrCounter "lex_trees"        tl+                   -- node count after polarities are taken into account+                   incrCounter "plex_subst_nodes" snl2+                   incrCounter "plex_foot_nodes"  anl2+                   incrCounter "plex_nodes"        nl2+                   incrCounter "plex_trees"        tl2+                where (tl , nl , snl , anl ) = countsFor cands+                      (tl2, nl2, snl2, anl2) = countsFor cands2+      -- 3 step through the whole thing+      stepAll_ = do countUp+                    incrCounter "pol_used_bundles" $ length autpaths+                    incrCounter "pol_used_paths"   $ length . automatonPaths . prFinal   $ autstuff+                    incrCounter "pol_seed_paths"   $ length . automatonPaths . prInitial $ autstuff+                    incrCounter "pol_total_states" $ sum $ map numStates auts+                    incrCounter "pol_total_trans"  $ sum $ map numTransitions auts+                    incrCounter "pol_max_states"   $ maximum $ map numStates auts+                    incrCounter "pol_max_trans"    $ maximum $ map numTransitions auts+                    stepAll builder+  in runState (execStateT stepAll_ iSt) iStats++-- ----------------------------------------------------------------------+-- Semantics and bit vectors+-- ----------------------------------------------------------------------++type SemBitMap = Map.Map (Literal GeniVal) BitVector++-- | assign a bit vector value to each literal in the semantics+-- the resulting map can then be used to construct a bit vector+-- representation of the semantics+defineSemanticBits :: Sem -> SemBitMap+defineSemanticBits sem = Map.fromList $ zip sem bits+  where+   bits = map bit [0..] -- 0001, 0010, 0100...++semToBitVector :: SemBitMap -> Sem -> BitVector+semToBitVector bmap sem = foldr (.|.) 0 $ map doLookup sem+  where doLookup p =+         case Map.lookup p bmap of+         Nothing -> geniBug $ "predicate " ++ prettyStr p ++ " not found in semanticBit map"+         Just b  -> b++bitVectorToSem :: SemBitMap -> BitVector -> Sem+bitVectorToSem bmap vector =+  mapMaybe tryKey $ Map.toList bmap+  where tryKey (p,k) = if (k .&. vector == k) then Just p else Nothing++-- ----------------------------------------------------------------------+-- Generate step+-- ----------------------------------------------------------------------++-- | Default implementation for the 'stepAll' function in 'Builder'+defaultStepAll :: Builder st it pa -> BuilderState st ()+defaultStepAll b =+ do s <- get+    case finished b s of+      Active -> step b >> defaultStepAll b+      _      -> return ()++-- | Dispatching consists of assigning a chart item to the right part of the+--   chart (agenda, trash, results list, etc).  This is implemented as a+--   series of filters which can either fail or succeed.  If a filter fails,+--   it may modify the item before passing it on to future filters.+type DispatchFilter s a = a -> s (FilterStatus a)++data FilterStatus a = Filtered | NotFiltered a++-- | Sequence two dispatch filters.+(>-->) :: (Monad s) => DispatchFilter s a -> DispatchFilter s a -> DispatchFilter s a+f >--> f2 = \x -> f x >>= next+ where+  next y@Filtered = return y+  next (NotFiltered x2) = f2 x2++-- | If the item meets some condition, use the first filter, otherwise+--   use the second one.+condFilter :: (Monad s) => (a -> Bool)+           -> DispatchFilter s a -> DispatchFilter s a+           -> DispatchFilter s a+condFilter cond f1 f2 = \x -> if cond x then f1 x else f2 x++-- ----------------------------------------------------------------------+-- Statistics+-- ----------------------------------------------------------------------++modifyStats :: (Metric -> Metric) -> BuilderState st ()+modifyStats fn = lift $ modify $ updateMetrics fn++incrCounter :: String -> Int -> BuilderState st ()+incrCounter key n = modifyStats (incrIntMetric key n)++queryCounter :: String -> Statistics -> Maybe Int+queryCounter key s =+  case queryMetrics (queryIntMetric key) s of+  []  -> Nothing+  [c] -> Just c+  _   -> geniBug $ "More than one instance of the metric: " ++ key++-- Command line configuration++initStats :: Params -> Statistics+initStats pa =+ let mdefault ms = if "default" `elem` ms then defaultMetricNames else []+     identifyMs :: [String] -> [Metric]+     identifyMs ms = map namedMetric $ mdefault ms ++ delete "default" ms+     metrics = identifyMs $ fromMaybe [] $ getFlagP MetricsFlg pa+ in execState (mapM_ addMetric metrics) emptyStats++namedMetric :: String -> Metric+-- the default case is that it's an int metric+namedMetric n = IntMetric n 0++-- Note that the strings here are command-line strings, not metric names!+defaultMetricNames :: [ String ]+defaultMetricNames = [ num_iterations, chart_size, num_comparisons, gen_time ]++-- Common counters+--+-- These numbers allow us to keep track of how efficient our generator is+-- and where we are in the process (how many steps we've taken, etc)++num_iterations, chart_size, num_comparisons, gen_time :: String++num_iterations  = "iterations"+chart_size      = "chart_size"+num_comparisons = "comparisons"+gen_time = "gen_time"++-- ----------------------------------------------------------------------+-- strictly API-ish bits+-- ----------------------------------------------------------------------++-- | The names of lexically selected chart items used in a derivation+lexicalSelection :: TagDerivation -> [Text]+lexicalSelection = sort . nub+                 . concatMap (\d -> dsChild d : maybeToList (dsParent d))++{-!+deriving instance NFData Input+!-}++-- GENERATED START++ +instance NFData Input where+        rnf (Input x1 x2 x3) = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` ()++-- GENERATED STOP
− src/NLP/GenI/Builder.lhs
@@ -1,562 +0,0 @@-% GenI surface realiser-% Copyright (C) 2005 Carlos Areces and Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.--\chapter{Builder}-\label{cha:Builder}--The heavy lifting of GenI, the whole chart/agenda mechanism, can be-implemented in many ways.  To make it easier to write different-algorithms for GenI and compare them, we provide a single interface-for what we call Builders.--This interface is then used called by the Geni module and by the-graphical interface.  Note that each builder has its own graphical-interface and that we do a similar thing in the graphical interface-code to make it possible to use these GUIs.  Maybe a little dose of-UML might help.  See figure \ref{fig:builderUml}.--\begin{figure}-\begin{center}-\includegraphics[scale=0.5]{images/builderUml.pdf}-\label{fig:builderUml}-\caption{Essentially what the Builder interface provides}-\end{center}-\end{figure}--\ignore{-\begin{code}-module NLP.GenI.Builder-where--import Control.Applicative ( (<$>), (<*>) )-import Control.Monad.State.Strict-import Data.Bits ( (.&.), (.|.), bit, xor )-import Data.List ( (\\), maximum, delete, sort, nub )-import qualified Data.Map as Map-import Data.Maybe ( mapMaybe, fromMaybe  )-import qualified Data.Set as Set-import Data.Tree ( flatten )-import Prelude hiding ( init )-import Text.JSON--import Data.Generics.PlateDirect-import Data.Generics ( Data )-import Data.Typeable ( Typeable )--import NLP.GenI.Automaton (NFA, automatonPaths, automatonPathSets, numStates, numTransitions)-import NLP.GenI.Configuration-  ( getListFlagP, getFlagP, Params,-    DetectPolaritiesFlg(..),-    ExtraPolaritiesFlg(..), MetricsFlg(..),-    RootFeatureFlg(..),-    Optimisation(..), hasOpt,-  )-import NLP.GenI.General (geniBug, BitVector, multiGroupByFM, fst3, snd3, thd3)-import NLP.GenI.Btypes-  ( ILexEntry, SemInput, Sem, Pred, showPred, showSem,-    AvPair(..), Flist, showFlist, gtype, GType(Subs, Foot),-    DescendGeniVal(..), Collectable(collect), alphaConvertById,-    GeniVal(GConst)-  )-import NLP.GenI.GeniParsers ( geniFeats, runParser, CharParser )-import NLP.GenI.Polarity  (PolResult, buildAutomaton, detectPolPaths)-import NLP.GenI.Statistics (Statistics, incrIntMetric,-                   Metric(IntMetric), updateMetrics,-                   queryMetrics, queryIntMetric,-                   addMetric, emptyStats,-                   )-import NLP.GenI.Tags ( TagElem(idname,tsemantics,ttree), setTidnums, TagDerivation, DerivationStep(..) )-\end{code}-}--\section{The interface}--All backends provide the same essential functionality:-\begin{description}-\item [run]       calls init and stepAll and potentially wraps it with some-                  other functionality.  -\item [init]      initialise the machine from the semantics and lexical selection -\item [step]      run a realisation step-\item [stepAll]   run all realisations steps until completion-\item [finished]  determine if realisation is finished-\item [stats]     extract various statistics from it-\item [setStats]  set the statistical information -\item [unpack]    unpack chart results into a list of sentences-\end{description}--FIXME: need to update this comment--\begin{code}-data Builder st it pa = Builder-  { init     :: Input -> pa -> (st, Statistics)-  ---  , step     :: BuilderState st ()-  , stepAll  :: BuilderState st ()-  ---  , finished :: st -> Bool-  , unpack   :: st -> [Output]-  , partial  :: st -> [Output] }--type Output = (LemmaPlusSentence, Derivation)-type Derivation = TagDerivation-\end{code}--To simplify interaction with the backend, we provide a single data-structure which represents all the inputs a backend could take.--\begin{code}-data Input = -  Input { inSemInput :: SemInput-        , inLex      :: [ILexEntry] -- ^ for the debugger-        , inCands    :: [(TagElem, BitVector)]   -- ^ tag tree-        }-\end{code}--\section{Uninflected words and sentences}--Each word of an uninflected sentence consists of a lemma and some-feature structures.--\paragraph -A SentenceAut represents a set of sentences in the form of an automaton.-The labels of the automaton are the words of the sentence.  But note! -``word'' in the sentence is in fact a tuple (lemma, inflectional feature-structures).  Normally, the states are defined as integers, with the-only requirement being that each one, naturally enough, is unique.--\begin{code}-type SentenceAut            = NFA Int LemmaPlus--data UninflectedDisjunction = UninflectedDisjunction [String] Flist deriving (Show, Data, Typeable)--instance Biplate UninflectedDisjunction GeniVal where-  biplate (UninflectedDisjunction a v) = plate UninflectedDisjunction |- a ||+ v--instance DescendGeniVal UninflectedDisjunction where-  descendGeniVal s (UninflectedDisjunction a v) = {-# SCC "descendGeniVal" #-} UninflectedDisjunction a (descendGeniVal s v)--instance Collectable UninflectedDisjunction where-  collect (UninflectedDisjunction _ b) = collect b-\end{code}--\section{BuilderState}--To cleanly seperate the tracking of statistics from the core functionality of a-builder, we use a State transformer to thread a Statistics state monad inside of-our main monad.--\begin{code}-type BuilderState s a = StateT s (State Statistics) a-\end{code}--\section{Helper functions for Builders}--\subsection{Initialisation}-\label{fn:Builder:preInit}--There's a few things that need to be run before even initialising the builder.-One of these is running some of the optimisations (namely the polarity stuff),-which is made complicated by the fact that they are optional.  Another of these-to assign each of the trees with a unique ID.  Note that this has to be done-after the polarity optimisation because this optimisation may introduce new-items into the lexical selection.  Finally, we must also make sure we perform-alpha conversion so that unification does not do the wrong thing when two trees-have the same variables.--\begin{code}-preInit :: Input -> Params -> (Input, (Int,Int,Int), PolResult)-preInit input config =- let (cand,_) = unzip $ inCands input-     seminput = inSemInput input-     ---     extraPol = fromMaybe (Map.empty) $ getFlagP ExtraPolaritiesFlg config-     polsToDetect = fromMaybe (error "there should be a default for --detect-pols")-                  $ getFlagP DetectPolaritiesFlg config-     rootFeat = getListFlagP RootFeatureFlg config-     -- do any optimisations-     isPol = hasOpt Polarised config-     -- polarity optimisation (if enabled)-     autstuff = buildAutomaton polsToDetect rootFeat extraPol seminput cand-     (_, seedAut, aut, sem2) = autstuff-     autpaths = map concat $ automatonPathSets aut-     combosPol = if isPol then autpaths else [cand]-     -- chart sharing optimisation-     (cands2, pathIds) = unzip $ detectPolPaths combosPol-     -- the number of paths explored vs possible-     polcount = (length autpaths, length $ automatonPaths aut, length $ automatonPaths seedAut)-     ---     fixate ts ps = zip (map alphaConvertById $ setTidnums ts) ps-     input2 = input { inCands    = fixate cands2 pathIds-                    , inSemInput = (sem2, snd3 seminput, thd3 seminput) }-     -- note: autstuff is only useful for the graphical debugger-  in (input2, polcount, autstuff)-\end{code}--\begin{code}--- | Equivalent to 'id' unless the input contains an empty or uninstatiated---   semantics-unlessEmptySem :: Input -> Params -> a -> a-unlessEmptySem input _ =- let (cands,_) = unzip $ inCands input-     nullSemCands   = [ idname t | t <- cands, (null.tsemantics) t ]-     unInstSemCands = [ idname t | t <- cands, not $ Set.null $ collect (tsemantics t) Set.empty ]-     nullSemErr     = "The following trees have a null semantics: " ++ (unwords nullSemCands)-     unInstSemErr   = "The following trees have an uninstantiated semantics: " ++ (unwords unInstSemCands)-     semanticsErr   = (if null nullSemCands then "" else nullSemErr ++ "\n") ++-                      (if null unInstSemCands then "" else unInstSemErr)-  in if null semanticsErr-     then id-     else error semanticsErr-\end{code}--\subsection{Running a surface realiser}--\begin{code}--- | Performs surface realisation from an input semantics and a lexical selection.------   Statistics tracked------    * pol_used_bundles - number of bundled paths through the polarity automaton.---                         see 'NLP.GenI.Automaton.automatonPathSets'------    * pol_used_paths - number of paths through the final automaton------    * pol_seed_paths - number of paths through the seed automaton (i.e. with no polarities).---                       This is normally just 1, unless you have multi-literal semantics------    * pol_total_states - combined number of states in the all the polarity automata------    * pol_total_tras - combined number of transitions in all polarity automata------    * pol_max_states - number of states in the polarity automaton with the most states------    * pol_total_tras - number of transitions in the polarity automata with the most transitions-run :: Builder st it Params -> Input -> Params -> (st, Statistics)-run builder input config =-  let -- 1 run the setup stuff-      (input2, polcount, autstuff) = preInit input config-      auts = (\(x,_,_,_) -> map snd3 x) autstuff-      -- 2 call the init stuff-      (iSt, iStats) = init builder input2 config-      -- 3 step through the whole thing-      stepAll_ = do incrCounter "pol_used_bundles" $ fst3 polcount-                    incrCounter "pol_used_paths"   $ snd3 polcount-                    incrCounter "pol_seed_paths"   $ thd3 polcount-                    incrCounter "pol_total_states" $ sum $ map numStates auts-                    incrCounter "pol_total_trans"  $ sum $ map numTransitions auts-                    incrCounter "pol_max_states"   $ maximum $ map numStates auts-                    incrCounter "pol_max_trans"    $ maximum $ map numTransitions auts-                    stepAll builder-  in runState (execStateT stepAll_ iSt) iStats-\end{code}--\subsection{Semantics and bit vectors}--\begin{code}-type SemBitMap = Map.Map Pred BitVector---- | assign a bit vector value to each literal in the semantics--- the resulting map can then be used to construct a bit vector--- representation of the semantics-defineSemanticBits :: Sem -> SemBitMap-defineSemanticBits sem = Map.fromList $ zip sem bits-  where-   bits = map bit [0..] -- 0001, 0010, 0100...--semToBitVector :: SemBitMap -> Sem -> BitVector-semToBitVector bmap sem = foldr (.|.) 0 $ map doLookup sem-  where doLookup p =-         case Map.lookup p bmap of-         Nothing -> geniBug $ "predicate " ++ showPred p ++ " not found in semanticBit map"-         Just b  -> b--bitVectorToSem :: SemBitMap -> BitVector -> Sem-bitVectorToSem bmap vector =-  mapMaybe tryKey $ Map.toList bmap-  where tryKey (p,k) = if (k .&. vector == k) then Just p else Nothing-\end{code}--\subsection{Index accesibility filtering}-\label{sec:iaf}--Index accesibility filtering was described in \cite{carroll05her}.  This-is my attempt to adapt it to TAG.  This filter works as a form of delayed-substitution, basically the exact opposite of delayed adjunction.--This might be wrong, but we say that an index is originally accesible if-it is the root node's idx attribute (no atomic disjunction; atomic-disjunction is as good as a variable as far I'm concerned)--FIXME: more about this later.-FIXME: are we sure we got the atomic disjunctions right?--\begin{code}-type IafMap = Map.Map String Sem---- | Return the literals of the semantics (in bit vector form)---   whose accesibility depends on the given index-dependentSem :: IafMap -> String -> Sem-dependentSem iafMap x = Map.findWithDefault [] x iafMap---- | Return the handle and arguments of a literal-literalArgs :: Pred -> [GeniVal]-literalArgs (h,_,args) = h:args--semToIafMap :: Sem -> IafMap-semToIafMap sem =-  multiGroupByFM (concatMap fromUniConst . literalArgs) sem---- | Like 'fromGConst' but only for the non-disjoint ones: meant to be used as Maybe or List-fromUniConst :: (Monad m) => GeniVal -> m String-fromUniConst (GConst [x]) = return x-fromUniConst _ = fail "not a unique constant" -- we don't actually expect this failure msg to be used--getIdx :: Flist -> [GeniVal]-getIdx fs = [ v | AvPair "idx" v <- fs ]--ts_iafFailure :: [String] -> [Pred] -> String-ts_iafFailure is sem = "index accesibility failure -" ++ (unwords is) ++ "- blocked: " ++ showSem sem---- | Calculate the new set of accessibility/inaccesible indices, returning a---   a tuple of accesible / inaccesible indices-recalculateAccesibility :: (IafAble a) => a -> a-recalculateAccesibility i =-  let oldAcc = iafAcc i-      newAcc = iafNewAcc i-      oldInacc = iafInacc i-      newInacc = oldInacc ++ (oldAcc \\ newAcc)-  in iafSetInacc newInacc $ iafSetAcc newAcc i---- | Return, in bitvector form, the portion of a semantics that is inaccesible---   from an item-iafBadSem :: (IafAble a) => IafMap -> SemBitMap-          -> BitVector -- ^ the input semantics-          -> (a -> BitVector) -- ^ the semantics of the item-          -> a -> BitVector-iafBadSem iafMap bmap sem semfn i =-  let -- the semantics we can't reach-      inaccessible = foldr (.|.) 0 $ map (semToBitVector bmap . dependentSem iafMap) $ iafInacc i-      -- the semantics we still _need_ to be able to reach-      remaining = sem `xor` (semfn i)-      -- where we're in trouble-  in inaccessible .&. remaining--class IafAble a where-  iafAcc      :: a -> [String]-  iafInacc    :: a -> [String]-  iafSetAcc   :: [String] -> a -> a-  iafSetInacc :: [String] -> a -> a-  iafNewAcc   :: a -> [String]-\end{code}--\subsection{Generate step}--\begin{code}--- | Default implementation for the 'stepAll' function in 'Builder'-defaultStepAll :: Builder st it pa -> BuilderState st ()-defaultStepAll b =- do s <- get-    unless (finished b s) $-      do step b-         defaultStepAll b-\end{code}--\subsection{Dispatching new chart items}-\label{sec:dispatching}--Dispatching consists of assigning a chart item to the right part of the-chart (agenda, trash, results list, etc).  This is implemented as a-series of filters which can either fail or succeed.--Counter-intuitively, success is defined as returning \verb!Nothing!.-Failure is defined as return \verb!Just!, because if a filter fails, it-has the right to modify the item for the next filter.  For example, the-top and bottom unification filter succeeds if it \emph{cannot} unify-the top and bottom features of a node.  It suceeds by putting the item-into the trash and returning Nothing.  If it \emph{can} perform top and-bottom unification, we want to return the item where the top and bottom-nodes are unified.  Failure is success, war is peace, freedom is-slavery, erase is backspace.--\begin{code}-type DispatchFilter s a = a -> s (Maybe a)---- | Sequence two dispatch filters.-(>-->) :: (Monad s) => DispatchFilter s a -> DispatchFilter s a -> DispatchFilter s a-f >--> f2 = \x -> f x >>= maybe (return Nothing) f2---- | A filter that always fails (i.e. no filtering)-nullFilter :: (Monad s) => DispatchFilter s a-nullFilter = return.Just---- | If the item meets some condition, use the first filter, otherwise---   use the second one.-condFilter :: (Monad s) => (a -> Bool)-           -> DispatchFilter s a -> DispatchFilter s a-           -> DispatchFilter s a-condFilter cond f1 f2 = \x -> if cond x then f1 x else f2 x-\end{code}--\subsection{Statistics}--\begin{code}-modifyStats :: (Metric -> Metric) -> BuilderState st ()-modifyStats fn = lift $ modify $ updateMetrics fn--incrCounter :: String -> Int -> BuilderState st ()-incrCounter key n = modifyStats (incrIntMetric key n)--queryCounter :: String -> Statistics -> Maybe Int-queryCounter key s =-  case queryMetrics (queryIntMetric key) s of-  []  -> Nothing-  [c] -> Just c-  _   -> geniBug $ "More than one instance of the metric: " ++ key-\end{code}--\subsection{Command line configuration}--\begin{code}-initStats :: Params -> Statistics-initStats pa =- let mdefault ms = if "default" `elem` ms then defaultMetricNames else []-     identifyMs :: [String] -> [Metric]-     identifyMs ms = map namedMetric $ mdefault ms ++ delete "default" ms-     metrics = identifyMs $ fromMaybe [] $ getFlagP MetricsFlg pa- in execState (mapM addMetric metrics) emptyStats--namedMetric :: String -> Metric--- the default case is that it's an int metric-namedMetric n = IntMetric n 0---- Note that the strings here are command-line strings, not metric names!-defaultMetricNames :: [ String ]-defaultMetricNames = [ num_iterations, chart_size, num_comparisons ]-\end{code}--\subsection{Common counters}--These numbers allow us to keep track of how efficient our generator is-and where we are in the process (how many steps we've taken, etc)--\begin{code}-num_iterations, chart_size, num_comparisons :: String--num_iterations  = "iterations"-chart_size      = "chart_size"-num_comparisons = "comparisons"-\end{code}--\section{The null builder}--For the purposes of tracking certain statistics without interfering with the-lazy evaluation of the real builders.  For example, one we would like to be-able to do is count the number of substitution and foot nodes in the lexical-selection.  Doing so would in a real builder might cause it to walk entire-trees for ptoentially no good reason.--\begin{code}-nullBuilder :: Builder () (NullState ()) Params-nullBuilder = Builder-  { NLP.GenI.Builder.init = initNullBuilder-  , step         = return ()-  , stepAll      = return ()-  , finished     = const True-  , unpack       = return []-  , partial      = return []-  }--type NullState a = BuilderState () a---- | Running the null builder allows you to track certain statistics------    * sem_literals    - number of literals in the input semantics------    * lex_trees       - total number of lexically selected trees----    * lex_foot_nodes  - total number of nodes of any sort in lexically selected trees------    * lex_subst_nodes - total number of sustitution nodes in lexically selected trees------    * lex_foot_nodes  - total number of foot nodes in lexically selected trees------    * plex_...        - same as the lex_ equivalent, but after polarity filtering-initNullBuilder ::  Input -> Params -> ((), Statistics)-initNullBuilder input config =-  let countsFor ts = (length ts, length nodes, length sn, length an)-        where nodes = concatMap (flatten.ttree) ts-              sn = [ n | n <- nodes, gtype n == Subs  ]-              an = [ n | n <- nodes, gtype n == Foot  ]-      ---      (tsem,_,_) = inSemInput input-      cands = map fst $ inCands input-      (_,_,(_,_,aut,_)) = preInit input config-      cands2 = concatMap concat $ automatonPathSets aut-      ---      countUp = do incrCounter "sem_literals"  $ length tsem-                   ---                   incrCounter "lex_subst_nodes" snl-                   incrCounter "lex_foot_nodes"  anl-                   incrCounter "lex_nodes"        nl-                   incrCounter "lex_trees"        tl-                   -- node count after polarities are taken into account-                   incrCounter "plex_subst_nodes" snl2-                   incrCounter "plex_foot_nodes"  anl2-                   incrCounter "plex_nodes"        nl2-                   incrCounter "plex_trees"        tl2-                where (tl , nl , snl , anl ) = countsFor cands-                      (tl2, nl2, snl2, anl2) = countsFor cands2-  in runState (execStateT countUp ()) (initStats config)-\end{code}--% -----------------------------------------------------------------------% strictly API-ish bits-% ------------------------------------------------------------------------\ignore{-\begin{code}--- | The names of lexically selected chart items used in a derivation-lexicalSelection :: Derivation -> [String]-lexicalSelection = sort . nub . concatMap (\d -> [dsChild d, dsParent d])---- | A lemma plus its morphological features-data LemmaPlus = LemmaPlus { lpLemma :: String-                           , lpFeats ::  Flist }- deriving (Show, Eq, Ord)---- | A sentence composed of 'LemmaPlus' instead of plain old words-type LemmaPlusSentence = [LemmaPlus]--instance JSON LemmaPlus where- readJSON j =-    do jo <- fromJSObject `fmap` readJSON j-       let field x = maybe (fail $ "Could not find: " ++ x) readJSON-                   $ lookup x jo-       LemmaPlus <$> field "lemma"-                 <*> (parsecToJSON "lemma-features" geniFeats =<< field "lemma-features")- showJSON (LemmaPlus l fs) =-     JSObject . toJSObject $ [ ("lemma", showJSON l)-                             , ("lemma-features", showJSON $ showFlist fs)-                             ]--parsecToJSON :: Monad m => String -> CharParser () b -> String -> m b-parsecToJSON description p str =- case runParser p () "" str of-   Left  err -> fail $ "Couldn't parse " ++ description ++ " because " ++ show err-   Right res -> return res-\end{code}-}
− src/NLP/GenI/BuilderGui.lhs
@@ -1,34 +0,0 @@-% GenI surface realiser-% Copyright (C) 2005 Carlos Areces and Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.--\begin{code}-module NLP.GenI.BuilderGui-where--import Graphics.UI.WX--import qualified NLP.GenI.Builder as B-import NLP.GenI.Geni (ProgStateRef, GeniResult)-import NLP.GenI.Configuration (Params)-import NLP.GenI.Statistics (Statistics)-\end{code}--\begin{code}-data BuilderGui = BuilderGui-  { resultsPnl  :: forall a . ProgStateRef -> (Window a) -> IO ([GeniResult],Statistics,Layout)-  , debuggerPnl :: forall a . (Window a) -> Params -> B.Input -> String -> IO Layout }-\end{code}
+ src/NLP/GenI/Configuration.hs view
@@ -0,0 +1,735 @@+-- GenI surface realiser+-- Copyright (C) 2005 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.++{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE OverloadedStrings, ViewPatterns #-}+module NLP.GenI.Configuration+    ( Params(..)+    --+    , mainBuilderTypes+    , getFlagP, getListFlagP, modifyFlagP, setFlagP, hasFlagP, deleteFlagP, hasOpt+    , emptyParams, defineParams+    , treatArgs, treatArgsWithParams, usage, basicSections, optionsSections+    , processInstructions+    , optionsForStandardGenI+    , optionsForBasicStuff, optionsForOptimisation, optionsForMorphology, optionsForInputFiles+    , optionsForBuilder, optionsForTesting+    , helpOption, verboseOption, macrosOption, lexiconOption+    , nubBySwitches+    , noArg, reqArg, optArg+    , parseFlagWithParsec+    -- * configration files+    , readGlobalConfig, setLoggers+    -- re-exports+    , module System.Console.GetOpt+    , module NLP.GenI.Flag+    , Typeable+    )+where++import Control.Applicative ( (<$>), pure )+import Control.Arrow ( first )+import Control.Monad ( liftM )+import Data.Char ( toLower, isSpace )+import Data.List  ( find, intersperse, nubBy )+import Data.Maybe ( fromMaybe, isNothing, fromJust )+import Data.Maybe ( listToMaybe, mapMaybe )+import Data.String ( IsString(..) )+import Data.Text ( Text )+import Data.Typeable ( Typeable )+import System.Directory ( getAppUserDataDirectory, doesFileExist )+import System.Environment ( getProgName )+import System.FilePath+import System.IO ( stderr )+import Text.ParserCombinators.Parsec ( runParser, CharParser )+import qualified Data.ByteString.Char8 as BC+import qualified Data.Map as Map+import qualified Data.Text as T+import qualified Data.Text.IO as T++import Data.Yaml.YamlLight+import System.Console.GetOpt+import System.Log.Formatter+import System.Log.Handler ( LogHandler, setFormatter )+import System.Log.Handler.Simple+import System.Log.Logger++import NLP.GenI.Flag+import NLP.GenI.General ( geniBug, fst3, snd3 )+import NLP.GenI.Parser ( geniFeats, tillEof )+import NLP.GenI.Morphology.Types ( MorphRealiser )+import NLP.GenI.Pretty+import NLP.GenI.Polarity.Types ( readPolarityAttrs )+import NLP.GenI.LexicalSelection ( LexicalSelector )++-- --------------------------------------------------------------------+-- Params+-- --------------------------------------------------------------------++-- | Holds the specification for how Geni should be run, its input+--   files, etc.  This is the stuff that would normally be found in+--   the configuration file.+data Params = Params+    { grammarType    :: GrammarType+    , builderType    :: BuilderType+    -- | Can still be overridden with a morph command mind you+    , customMorph    :: Maybe MorphRealiser+    -- | Lexical selection function+    --   (if you set this you may want to add 'PreAnchored' to the config)+    , customSelector :: Maybe LexicalSelector+    , geniFlags      :: [Flag]+    }++{-+instance Show Params where+    show p = unlines+        [ unwords [ "GenI config :", show (grammarType p), show (builderType p), morph ]+        , unwords $ "GenI flags  :" : map show (geniFlags p)+        ]+      where+        morph = "custom morph:" ++ show (isJust (customMorph p))+-}++-- | The default parameters configuration+emptyParams :: Params+emptyParams = Params+    { builderType    = SimpleBuilder+    , grammarType    = GeniHand+    , customMorph    = Nothing+    , customSelector = Nothing+    , geniFlags      = emptyFlags+    }++hasOpt :: Optimisation -> Params -> Bool+hasOpt o p = maybe False (elem o) $ getFlagP OptimisationsFlg p++hasFlagP    :: (Typeable f, Typeable x) => (x -> f) -> Params -> Bool+hasFlagP f      = hasFlag f . geniFlags++deleteFlagP :: (Typeable f, Typeable x) => (x -> f) -> Params -> Params+deleteFlagP f p = p { geniFlags = deleteFlag f (geniFlags p) }++modifyFlagP :: (Eq f, Typeable f, Typeable x)+            => (x -> f) -> (x -> x) -> Params -> Params+modifyFlagP f m p = p { geniFlags = modifyFlag f m (geniFlags p) }++setFlagP    :: (Eq f, Typeable f, Typeable x)+            => (x -> f) -> x -> Params -> Params+setFlagP f v p  = p { geniFlags = setFlag f v (geniFlags p) }++getFlagP    :: (Typeable f, Typeable x)+            => (x -> f) -> Params -> Maybe x+getFlagP f = getFlag f . geniFlags++getListFlagP :: (Typeable f, Typeable x)+             => ([x] -> f) -> Params -> [x]+getListFlagP f = fromMaybe [] . getFlagP f++emptyFlags :: [Flag]+emptyFlags =+    [ Flag ViewCmdFlg "ViewTAG"+    , Flag DetectPolaritiesFlg $+          readPolarityAttrs defaultPolarityAttrs+    , Flag RootFeatureFlg $+          parseFlagWithParsec "default root feat" geniFeats defaultRootFeat+    ]++-- --------------------------------------------------------------------+-- Command line arguments+-- --------------------------------------------------------------------++type OptSection = (String,[OptDescr Flag],[String])++-- | Uses the GetOpt library to process the command line arguments.+-- Note that we divide them into basic and advanced usage.+optionsForStandardGenI :: [OptDescr Flag]+optionsForStandardGenI =+    nubBySwitches $ concatMap snd3 optionsSections+        ++ [ Option ['p']    []  (reqArg WeirdFlg id "CMD") "" ]+        -- TODO: what is this -p flag for, exactly? It's something+        -- related to how GenI runs within an app bundle.  Can we+        -- do away with it?++basicSections :: [OptSection]+basicSections =+    map tweakBasic $ take 1 optionsSections+  where+    tweakBasic (x,y,z) = (x,y,z ++ ["See --help for more options"])++optionsSections :: [OptSection]+optionsSections =+    [ ("Core options", optionsForBasicStuff, example)+    , ("Input", optionsForInputFiles, [])+    , ("Output", optionsForOutput, [])+    , ("Algorithm",+        (nubBySwitches $ optionsForBuilder ++ optionsForOptimisation),+        usageForOptimisations)+    , ("Morphology", optionsForMorphology, [])+    , ("User interface", optionsForUserInterface, [])+    , ("Batch processing", optionsForTesting, [])+    ]+  where+      example =+          [ "Example:"+          , " geni -m examples/ej/mac -l examples/ej/lexicon -s examples/ej/suite"+          ]++getSwitches :: OptDescr a -> ([Char],[String])+getSwitches (Option s l _ _) = (s,l)++nubBySwitches :: [OptDescr a] -> [OptDescr a]+nubBySwitches = nubBy (\x y -> getSwitches x == getSwitches y)++-- GetOpt wrappers+noArg :: forall f . (Eq f, Typeable f)+      => (() -> f) -> ArgDescr Flag+noArg  s = NoArg (Flag s ())++reqArg :: forall f x . (Eq f, Typeable f, Eq x, Typeable x)+       => (x -> f)      -- ^ flag+       -> (String -> x) -- ^ string reader for flag (probably |id| if already a String)+       -> String        -- ^ description+       -> ArgDescr Flag+reqArg s fn desc = ReqArg (\x -> Flag s (fn x)) desc++optArg :: forall f x . (Eq f, Typeable f, Eq x, Typeable x)+       => (x -> f)       -- ^ flag+       -> x              -- ^ default value+       -> (String -> x)  -- ^ string reader (as in @reqArg@)+       -> String         -- ^ description+       -> ArgDescr Flag+optArg s def fn desc = OptArg (\x -> Flag s (maybe def fn x)) desc++-- -------------------------------------------------------------------+-- Parsing command line arguments+-- -------------------------------------------------------------------++-- | Print out a GenI-style usage message with options divided into sections+usage :: [OptSection] -- ^ options+      -> String -- ^ prog name+      -> String+usage sections pname =+ let header   = "Usage: " ++ pname ++ " [OPTION...]\n"+     body     = unlines $ map usageSection sections+ in header ++ body++usageSection :: (String, [OptDescr Flag],[String]) -> String+usageSection (name, opts, comments) =+ usageInfo (unlines $ [bar,name, bar]) opts ++ mcomments+ where+  bar = replicate 72 '='+  mcomments = if null comments then [] else "\n" ++ unlines comments++treatArgs :: [OptDescr Flag] -> [String] -> IO Params+treatArgs options argv = treatArgsWithParams options argv emptyParams++treatArgsWithParams :: [OptDescr Flag] -> [String] -> Params -> IO Params+treatArgsWithParams options argv initParams =+   case getOpt Permute options argv of+     (os,_,[]  )-> return $ defineParams os initParams+     (_,_,errs) -> do p <- getProgName+                      ioError (userError $ concat errs ++ usage basicSections p)++defineParams :: [Flag] -> Params -> Params+defineParams flgs prms =+  (\p -> foldr setDefault p $ geniFlags prms)+  . (mergeFlagsP OptimisationsFlg)+  . (mergeFlagsP MetricsFlg)+  $ prms+    { geniFlags     = flgs+    , builderType   = fromFlags builderType BuilderFlg flgs+    , grammarType   = fromFlags grammarType GrammarTypeFlg flgs+    }+ where+  setDefault (Flag f v) p =+    if hasFlagP f p then p else setFlagP f v p+  mergeFlagsP f p =+    if hasFlagP f p+    then setFlagP f (concat $ getAllFlags f flgs) p+    else p+  fromFlags default_ t fs =+    fromMaybe (default_ prms) (getFlag t fs)++-- --------------------------------------------------------------------+-- Basic options+-- --------------------------------------------------------------------++optionsForBasicStuff :: [OptDescr Flag]+optionsForBasicStuff =+  [ helpOption, verboseOption, noguiOption+  , macrosOption , lexiconOption, testSuiteOption+  , rootFeatureOption+  , outputOption+  ]++-- --------------------------------------------------------------------+-- Input files+-- --------------------------------------------------------------------++optionsForInputFiles :: [OptDescr Flag]+optionsForInputFiles =+  [ macrosOption+  , lexiconOption+  , tracesOption+  , testSuiteOption+  , fromStdinOption+  , morphInfoOption+  , instructionsOption+  , rankingOption+  , Option []    ["preselected"] (NoArg (Flag GrammarTypeFlg PreAnchored))+      "do NOT perform lexical selection - treat the grammar as the selection"+  ]++instructionsOption, macrosOption, lexiconOption, tracesOption :: OptDescr Flag++instructionsOption =+  Option [] ["instructions"] (reqArg InstructionsFileFlg id "FILE")+      "instructions file FILE"++macrosOption =+  Option ['t','m'] ["trees","macros"] (reqArg MacrosFlg id "FILE")+      "tree schemata file FILE (unanchored trees)"++lexiconOption =+  Option ['l'] ["lexicon"] (reqArg LexiconFlg id "FILE")+     "lexicon file FILE"++tracesOption =+  Option [] ["traces"] (reqArg TracesFlg id "FILE")+    "traces file FILE (list of traces to display)"++rankingOption :: OptDescr Flag+rankingOption =+  Option [] ["ranking"] (reqArg RankingConstraintsFlg id "FILE")+    "ranking constraints FILE (using Optimality Theory)"++-- --------------------------------------------------------------------+-- Output+-- --------------------------------------------------------------------++optionsForOutput :: [OptDescr Flag]+optionsForOutput =+  [ outputOption+  , Option []    ["dump"]    (noArg DumpDerivationFlg)+      "print derivation information on stdout (JSON)"+  -- same as rankingOption but with output-centric help text+  , partialOption+  , Option [] ["ranking"] (reqArg RankingConstraintsFlg id "FILE")+    "use constraints in FILE to rank output"+  ]++partialOption :: OptDescr Flag+partialOption =+ Option []    ["partial"] (noArg PartialFlg)+    "return partial result(s) if no complete solution is found"++outputOption :: OptDescr Flag+outputOption =+  Option ['o'] ["output"] (reqArg OutputFileFlg id "FILE")+    "output file FILE (stdout if unset)"++-- --------------------------------------------------------------------+-- User interface+-- --------------------------------------------------------------------++optionsForUserInterface :: [OptDescr Flag]+optionsForUserInterface =+  [ noguiOption, helpOption, versionOption+  , Option []    ["viewcmd"]  (reqArg ViewCmdFlg id "CMD")+      "XMG tree-view command"+  ]++noguiOption :: OptDescr Flag+noguiOption = Option [] ["nogui"] (noArg DisableGuiFlg)+                "disable graphical user interface"++helpOption :: OptDescr Flag+helpOption  = Option [] ["help"] (noArg HelpFlg)+                "show full list of command line switches"++versionOption :: OptDescr Flag+versionOption  = Option [] ["version"] (noArg VersionFlg)+                "display the version"++verboseOption :: OptDescr Flag+verboseOption = Option ['v'] ["verbose"] (noArg VerboseModeFlg)+                "verbose mode"++-- --------------------------------------------------------------------+-- Optimisations+-- --------------------------------------------------------------------++defaultPolarityAttrs :: String+defaultPolarityAttrs = "cat"++exampleRootFeat :: String+exampleRootFeat = "[cat:s inv:- mode:ind|subj wh:-]"++defaultRootFeat :: String+defaultRootFeat = "[cat:_]"++optionsForOptimisation :: [OptDescr Flag]+optionsForOptimisation =+   [ Option [] ["opts"]+         (reqArg OptimisationsFlg readOptimisations "LIST")+         "optimisations 'LIST' (--help for details)"+   , Option [] ["detect-pols"]+         (reqArg DetectPolaritiesFlg readPolarityAttrs "LIST")+         ("attributes 'LIST' (eg. \"cat idx V.tense\", default:" ++ show defaultPolarityAttrs ++ ")")+   , rootFeatureOption+   , maxResultsOption+  ]++rootFeatureOption :: OptDescr Flag+rootFeatureOption =+  Option ['r'] ["rootfeat"]+         (reqArg RootFeatureFlg readRF "FEATURE")+         ("root features 'FEATURE' (eg. "+          ++ prettyStr exampleRF ++ ", default: "+          ++ prettyStr defaultRF ++ ")")+ where+   exampleRF = readRF exampleRootFeat+   defaultRF = readRF defaultRootFeat+   readRF = parseFlagWithParsec "root feature" geniFeats++coreOptimisationCodes :: [(Optimisation,String,String)]+coreOptimisationCodes =+ [ (Polarised        , "p",      "polarity filtering")+ , (NoConstraints    , "nc",     "disable semantic constraints (anti-optimisation!)")+ ]++optimisationCodes :: [(Optimisation,String,String)]+optimisationCodes =+ coreOptimisationCodes +++ [ (PolOpts          , "pol",    equivalentTo polOpts)+ , (AdjOpts          , "adj",    equivalentTo adjOpts)+ ]+ where equivalentTo os = "equivalent to '" ++ (unwords $ map showOptCode os) ++ "'"++polOpts, adjOpts :: [Optimisation]+polOpts = [Polarised]+adjOpts = []++-- ---------------------------------------------------------------------+-- Optimisation usage info+-- ---------------------------------------------------------------------++lookupOpt:: Optimisation -> (String, String)+lookupOpt k =+ case find (\x -> k == fst3 x) optimisationCodes of+ Just (_, c, d) -> (c, d)+ Nothing -> geniBug $ "optimisation " ++  show k ++ " unknown"++showOptCode :: Optimisation -> String+showOptCode = fst.lookupOpt++describeOpt :: (Optimisation, String, String) -> String+describeOpt (_,k,d) = k ++ " - " ++ d++-- | Displays the usage text for optimisations.+--   It shows a table of optimisation codes and their meaning.+usageForOptimisations :: [String]+usageForOptimisations =+     [ "Optimisations must be passed in as a space-delimited list"+     , "(ex: --opt='p f-sem' for polarities and semantic filtering)"+     , ""+     , "Optimisations:"+     , "  " ++ unlinesTab (map describeOpt coreOptimisationCodes)+     ]+ where unlinesTab l = concat (intersperse "\n  " l)++-- ---------------------------------------------------------------------+-- Parsing optimisation stuff+-- ---------------------------------------------------------------------++-- | If we do not recognise a code, we output an error message.  We+--  also take the liberty of expanding thematic codes like 'pol'+--  into the respective list of optimisations.+readOptimisations :: String -> [Optimisation]+readOptimisations str =+  case parseOptimisations str of+    Left ick -> error $ "Unknown optimisations: " ++ (unwords ick)+    Right os -> (addif PolOpts polOpts) . (addif AdjOpts adjOpts) $ os+  where addif t x o = if (t `elem` o) then x ++ o else o++-- | Returns |Left| for any codes we don't recognise, or+--   |Right| if everything is ok.+parseOptimisations :: String -> Either [String] [Optimisation]+parseOptimisations str =+  let codes = words str+      mopts = map lookupOptimisation codes+  in if any isNothing mopts+     then Left  [ c | (c,o) <- zip codes mopts, isNothing o ]+     else Right $ map fromJust mopts++lookupOptimisation :: String -> Maybe Optimisation+lookupOptimisation code =+  liftM fst3 $ find (\x -> snd3 x == code) optimisationCodes++-- | TODO: This is a horrible and abusive use of 'error'+parseFlagWithParsec :: String -> CharParser () b -> String -> b+parseFlagWithParsec description p str =+ case runParser (tillEof p) () "" str of+ Left  err -> error $ "Couldn't parse " ++ description ++ " because " ++ show err+ Right res -> res++-- --------------------------------------------------------------------+-- Builders+-- --------------------------------------------------------------------++optionsForBuilder :: [OptDescr Flag]+optionsForBuilder =+  [ Option ['b'] ["builder"]  (reqArg BuilderFlg readBuilderType "BUILDER")+      ("use as realisation engine one of: " ++ (unwords $ map show mainBuilderTypes))+  , partialOption+  , maxStepsOption+  , maxResultsOption+  ]++mainBuilderTypes :: [BuilderType]+mainBuilderTypes =+ [ SimpleBuilder, SimpleOnePhaseBuilder+ ]++-- | Hint: compose with (map toLower) to make it case-insensitive+mReadBuilderType :: String -> Maybe BuilderType+mReadBuilderType "simple"    = Just SimpleBuilder+mReadBuilderType "simple-2p" = Just SimpleBuilder+mReadBuilderType "simple-1p" = Just SimpleOnePhaseBuilder+mReadBuilderType _           = Nothing++-- | Is case-insensitive, error if unknown type+readBuilderType :: String -> BuilderType+readBuilderType b =+  case mReadBuilderType $ map toLower b of+  Just x  -> x+  Nothing -> error $ "Unknown builder type " ++ b++-- --------------------------------------------------------------------+-- Testing and profiling+-- --------------------------------------------------------------------++fromStdinOption :: OptDescr Flag+fromStdinOption =+  Option [] ["from-stdin"] (noArg FromStdinFlg) "get testcase from stdin"++testSuiteOption :: OptDescr Flag+testSuiteOption =+  Option ['s'] ["testsuite"] (reqArg TestSuiteFlg id "FILE") "test suite FILE"++maxResultsOption :: OptDescr Flag+maxResultsOption =+  Option []    ["maxresults"] (reqArg MaxResultsFlg read "INT")+      "return as soon as at least INT results are found"++maxStepsOption :: OptDescr Flag+maxStepsOption =+  Option []    ["maxsteps"] (reqArg MaxStepsFlg read "INT")+      "abort and return any results found after INT steps"++optionsForTesting :: [OptDescr Flag]+optionsForTesting =+  [ testSuiteOption+  , fromStdinOption+  , Option []    ["testcase"]+      (reqArg (TestCaseFlg . T.pack) id "STRING")+      "run test case STRING"+  , Option []    ["timeout"] (reqArg TimeoutFlg read "SECONDS")+      "time out after SECONDS seconds"+  , maxResultsOption+  , maxStepsOption+  , Option []    ["metrics"] (optArg MetricsFlg ["default"] words "LIST")+      "keep track of performance metrics: (default: iterations comparisons chart_size)"+  , Option []    ["statsfile"] (reqArg StatsFileFlg id "FILE")+      "write performance data to file FILE (stdout if unset)"+  , Option []    ["batchdir"]    (reqArg BatchDirFlg id "DIR")+      "batch process the test suite and save results to DIR"+  , Option []    ["earlydeath"]    (noArg EarlyDeathFlg)+      "exit on first case with no results (batch processing) "+ ]++-- --------------------------------------------------------------------+-- Morphology+-- --------------------------------------------------------------------++optionsForMorphology :: [OptDescr Flag]+optionsForMorphology =+  [ morphInfoOption+  , Option []    ["morphcmd"]  (reqArg MorphCmdFlg id "CMD")+      "morphological post-processor CMD (default: unset)"+  ]++morphInfoOption :: OptDescr Flag+morphInfoOption = Option [] ["morphinfo"] (reqArg MorphInfoFlg id "FILE")+  "morphological features FILE (default: unset)"++-- ====================================================================+-- Scripting GenI+-- ====================================================================++-- | Update the internal instructions list, test suite and case+--   according to the contents of an instructions file.+--+--   Basic approach+--+--   * we always have instructions: if no instructions file, is specified+--     we infer virtual instructions from the test suite flag+--   * the testsuite and testcase flags are focusing tools, they pick out+--     a subset from the instructions+processInstructions :: Params -> IO Params+processInstructions config = do+    instructions <- case getFlagP InstructionsFileFlg config of+                      Nothing -> return fakeInstructions+                      Just f  -> instructionsFile `fmap` T.readFile f+    let updateInstructions = setFlagP TestInstructionsFlg instructions+        -- we have to set a test suite in case the user only supplies+        -- an instructions argument so that NLP.GenI.loadEverything+        -- knows that the user has given us a suite to load+        updateTestSuite p =+          if hasFlagP TestSuiteFlg p then p+             else case (fst `fmap` listToMaybe instructions) of+                   Just s  -> setFlagP TestSuiteFlg s p+                   Nothing -> p+    return . updateTestSuite . updateInstructions $ config+  where+    fakeInstructions :: [Instruction]+    fakeInstructions =+         let cases = singleton <$> getFlagP TestCaseFlg config+             mkInstr xs = singleton (xs, cases)+         in maybe [] mkInstr $ getFlagP TestSuiteFlg config++instructionsFile :: Text -> [Instruction]+instructionsFile =+    mapMaybe inst . T.lines+  where+    inst l = case T.words (T.takeWhile (/= '%') l) of+                 []     -> Nothing+                 [f]    -> Just (T.unpack f, Nothing)+                 (f:cs) -> Just (T.unpack f, Just cs)++-- ====================================================================+-- Configuration file+-- ====================================================================++readGlobalConfig :: IO (Maybe YamlLight)+readGlobalConfig = do+  geniCfgDir <- getAppUserDataDirectory "geni"+  let globalCfg = geniCfgDir </> "config.yaml"+  hasCfg <- doesFileExist globalCfg+  if hasCfg then Just `fmap` parseYamlFile globalCfg +            else return Nothing++data LoggerConfig = LoggerConfig { lcName      :: String+                                 , lcPriority  :: Priority+                                 , lcHandler   :: LogTo+                                 , lcFormatter :: LogFmt+                                 }+ deriving Show++data LogTo = LogToFile FilePath | LogToErr+ deriving Show++data LogFmt = LogFmtNull | LogFmtSimple String+ deriving Show++logDefaultConfig :: String -> LoggerConfig+logDefaultConfig n = LoggerConfig+    { lcName      = n+    , lcPriority  = DEBUG+    , lcHandler   = LogToErr+    , lcFormatter = LogFmtNull+    }++setLoggers :: YamlLight -> IO ()+setLoggers y = do+    -- it seems we need to explicitly create the root logger+    -- we set this to the lowest priority because we want the user to+    -- be able to set the priority on their loggers as low as they want +    updateGlobalLogger "" $ setLevel DEBUG+                          . setHandlers noHandlers+    mapM_ setGeniHandler $ fromMaybe [globalDefault] (loggerConfig y)+  where+    noHandlers :: [GenericHandler ()]+    noHandlers = []+    globalDefault = (logDefaultConfig "NLP.GenI") { lcPriority = INFO }++setGeniHandler :: LoggerConfig -> IO ()+setGeniHandler lc = do+    h <- flip setFormatter fmttr <$> handler (lcPriority lc)+    updateGlobalLogger (lcName lc) (setHandlers [h])+  where+    handler = case lcHandler lc of+                LogToFile f -> fileHandler f+                LogToErr    -> streamHandler stderr+    --+    fmttr = case lcFormatter lc of+              LogFmtSimple str -> simpleLogFormatter str+              LogFmtNull       -> nullFormatter++instance Read LogTo where+  readsPrec _ (dropPrefix "stderr"  -> ("", x)) = [ (LogToErr, x) ]+  readsPrec p (dropPrefix "file"    -> ("", x)) = map (first LogToFile) (readsQuotedStringPrec p x)+  readsPrec _ _ = []++instance Read LogFmt where+  readsPrec _ (dropPrefix "null"     -> ("", x)) = [ (LogFmtNull, x) ]+  readsPrec p (dropPrefix "simple"   -> ("", x)) = map (first LogFmtSimple) (readsQuotedStringPrec p x)+  readsPrec _ _ = []++readsQuotedStringPrec :: Int -> String -> [ (String, String) ]+readsQuotedStringPrec p x@(h:_) | isSpace h =+    case dropWhile isSpace x of+      xs@('"':_)                                -> readsPrec p xs+      (break isSpace -> y) | not (null (fst y)) -> [y]+      _                                         -> []+readsQuotedStringPrec _ _                   = []++loggerConfig :: YamlLight -> Maybe [LoggerConfig]+loggerConfig yaml = lookupYL "logging" yaml+                  >>= unSeq+                  >>= mapM unMap+                  >>= mapM readOne+ where+   readOne :: Map.Map YamlLight YamlLight -> Maybe LoggerConfig +   readOne m = do+     let name = fromMaybe "NLP.GenI" (get Just "name" m)+     return $ updater "level"   m (\x l -> l { lcPriority = x })+            . updater "handler" m (\x l -> l { lcHandler  = x })+            . updater "format"  m (\x l -> l { lcFormatter = x })+            $ logDefaultConfig name+   updater str m fn = maybe id fn (get maybeRead str m)+   get f x m = Map.lookup x m >>= unStr >>= (f . BC.unpack)++instance IsString YamlLight where+  fromString = YStr . fromString++-- ----------------------------------------------------------------------+--+-- ----------------------------------------------------------------------++singleton :: a -> [a]+singleton = pure++maybeRead :: Read a => String -> Maybe a+maybeRead s = case reads s of+  [(x, rest)] | all isSpace rest -> Just x+  _         -> Nothing++dropPrefix :: Eq a => [a] -> [a] -> ([a],[a])+dropPrefix (x:xs) (y:ys) | x == y    = dropPrefix xs ys+dropPrefix left right = (left,right)
− src/NLP/GenI/Configuration.lhs
@@ -1,891 +0,0 @@-% GenI surface realiser-% Copyright (C) 2005 Carlos Areces and Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.--\chapter{Command line arguments}--\begin{code}-{-# LANGUAGE ExistentialQuantification #-}-module NLP.GenI.Configuration-  ( Params(..), GrammarType(..), BuilderType(..), Instruction, Flag-  -- * flags-  , BatchDirFlg(..)-  , DetectPolaritiesFlg(..)-  , DisableGuiFlg(..)-  , DumpDerivationFlg(..)-  , EarlyDeathFlg(..)-  , ExtraPolaritiesFlg(..)-  , FromStdinFlg(..)-  , HelpFlg(..)-  , InstructionsFileFlg(..)-  , LexiconFlg(..)-  , MacrosFlg(..)-  , MetricsFlg(..)-  , MorphCmdFlg(..)-  , MorphInfoFlg(..)-  , NoLoadTestSuiteFlg(..)-  , OptimisationsFlg(..)-  , OutputFileFlg(..)-  , PartialFlg(..)-  , RankingConstraintsFlg(..)-  , RegressionTestModeFlg(..)-  , RootFeatureFlg(..)-  , RunUnitTestFlg(..)-  , StatsFileFlg(..)-  , TestCaseFlg(..)-  , TestInstructionsFlg(..)-  , TestSuiteFlg(..)-  , TimeoutFlg(..)-  , TracesFlg(..)-  , VerboseModeFlg(..)-  , VersionFlg(..)-  , ViewCmdFlg(..)-  ---  , mainBuilderTypes-  , getFlagP, getListFlagP, setFlagP, hasFlagP, deleteFlagP, hasOpt-  , getFlag, setFlag, hasFlag-  , Optimisation(..)-  , emptyParams, defineParams-  , treatArgs, treatArgsWithParams, usage, basicSections, optionsSections-  , processInstructions-  , optionsForStandardGenI-  , optionsForBasicStuff, optionsForOptimisation, optionsForMorphology, optionsForInputFiles-  , optionsForBuilder, optionsForTesting-  , nubBySwitches-  , noArg, reqArg, optArg-  , parseFlagWithParsec-  -- re-exports-  , module System.Console.GetOpt-  , Typeable-  )-where-\end{code}--\ignore{-\begin{code}-import qualified Data.Map as Map-import qualified Data.Set as Set--import Control.Monad ( liftM )-import Data.Char ( toLower )-import Data.Maybe ( listToMaybe, mapMaybe )-import Data.Typeable ( Typeable, typeOf, cast )-import System.Console.GetOpt-import System.Environment ( getProgName )-import Data.List  ( find, intersperse, nubBy )-import Data.Maybe ( catMaybes, fromMaybe, isNothing, fromJust )-import Text.ParserCombinators.Parsec ( runParser, CharParser )--import NLP.GenI.Btypes ( Flist, showFlist, )-import NLP.GenI.General ( geniBug, fst3, snd3, Interval )-import NLP.GenI.GeniParsers ( geniFeats, geniPolarities )-import NLP.GenI.PolarityTypes ( PolarityKey(..), PolarityAttr(..), readPolarityAttrs )-\end{code}-}--% ---------------------------------------------------------------------% Code for debugging. (should be latex-commented-% when not in use)-% ----------------------------------------------------------------------%\begin{code}-%import Debug.Trace-%\end{code}--% ---------------------------------------------------------------------% Params-% ----------------------------------------------------------------------\begin{code}--- | Holds the specification for how Geni should be run, its input---   files, etc.  This is the stuff that would normally be found in---   the configuration file.-data Params = Prms{-  grammarType    :: GrammarType,-  builderType    :: BuilderType,-  geniFlags      :: [Flag]-} deriving (Show)--hasOpt :: Optimisation -> Params -> Bool-hasOpt o p = maybe False (elem o) $ getFlagP OptimisationsFlg p--hasFlagP    :: (Typeable f, Typeable x) => (x -> f) -> Params -> Bool-deleteFlagP :: (Typeable f, Typeable x) => (x -> f) -> Params -> Params-setFlagP    :: (Eq f, Show f, Show x, Typeable f, Typeable x) => (x -> f) -> x -> Params -> Params-getFlagP    :: (Show f, Show x, Typeable f, Typeable x) => (x -> f) -> Params -> Maybe x-getListFlagP :: (Show f, Show x, Typeable f, Typeable x) => ([x] -> f) -> Params -> [x]--hasFlagP f      = hasFlag f . geniFlags-deleteFlagP f p = p { geniFlags = deleteFlag f (geniFlags p) }-setFlagP f v p  = p { geniFlags = setFlag f v (geniFlags p) }-getFlagP f     = getFlag f . geniFlags-getListFlagP f = fromMaybe [] . getFlagP f--- | The default parameters configuration-emptyParams :: Params-emptyParams = Prms {-  builderType   = SimpleBuilder,-  grammarType   = GeniHand,-  geniFlags     = [ Flag ViewCmdFlg "ViewTAG"-                  , Flag DetectPolaritiesFlg (readPolarityAttrs defaultPolarityAttrs)-                  , Flag RootFeatureFlg (readRF defaultRootFeat)-                  ]-}- where readRF = parseFlagWithParsec "default root feature" geniFeats-\end{code}--% ---------------------------------------------------------------------\section{Command line arguments}-% ----------------------------------------------------------------------Command line arguments can be specified in the GNU style, for example-\texttt{--foo=bar} or \texttt{--foo bar}, or \texttt{-f bar} when a-short switch is available.  For more information, type \texttt{geni---help}.---\begin{code}-type OptSection = (String,[OptDescr Flag],[String])---- | Uses the GetOpt library to process the command line arguments.--- Note that we divide them into basic and advanced usage.-optionsForStandardGenI :: [OptDescr Flag]-optionsForStandardGenI =-  nubBySwitches $ concatMap snd3 optionsSections-                  ++ -- FIXME: weird mac stuff-                  [ Option ['p']    []  (reqArg WeirdFlg id "CMD") "" ]--basicSections :: [OptSection]-basicSections = map tweakBasic $ take 1 optionsSections- where-  tweakBasic (x,y,z) = (x,y,z ++ ["See --help for more options"])--optionsSections :: [OptSection]-optionsSections =- [ ("Core options", optionsForBasicStuff, example)- , ("Input", optionsForInputFiles, [])- , ("Output", optionsForOutput, [])- , ("Algorithm",-     (nubBySwitches $ optionsForBuilder ++ optionsForOptimisation),-     usageForOptimisations)- , ("Morphology", optionsForMorphology, [])- , ("User interface", optionsForUserInterface, [])- , ("Batch processing", optionsForTesting, [])- ]- where-  example  = [ "Example:"-             , " geni -m examples/ej/mac -l examples/ej/lexicon -s examples/ej/suite"-             ]--getSwitches :: OptDescr a -> ([Char],[String])-getSwitches (Option s l _ _) = (s,l)--nubBySwitches :: [OptDescr a] -> [OptDescr a]-nubBySwitches = nubBy (\x y -> getSwitches x == getSwitches y)---- GetOpt wrappers-noArg :: forall f . (Eq f, Show f, Typeable f)-      => (() -> f) -> ArgDescr Flag-noArg  s = NoArg (Flag s ())--reqArg :: forall f x . (Eq f, Show f, Typeable f, Eq x, Show x, Typeable x)-       => (x -> f)      -- ^ flag-       -> (String -> x) -- ^ string reader for flag (probably |id| if already a String)-       -> String        -- ^ description-       -> ArgDescr Flag-reqArg s fn desc = ReqArg (\x -> Flag s (fn x)) desc--optArg :: forall f x . (Eq f, Show f, Typeable f, Eq x, Show x, Typeable x)-       => (x -> f)       -- ^ flag-       -> x              -- ^ default value-       -> (String -> x)  -- ^ string reader (as in @reqArg@)-       -> String         -- ^ description-       -> ArgDescr Flag-optArg s def fn desc = OptArg (\x -> Flag s (maybe def fn x)) desc-\end{code}--\begin{code}--- ---------------------------------------------------------------------- Parsing command line arguments--- ----------------------------------------------------------------------- | Print out a GenI-style usage message with options divided into sections-usage :: [OptSection] -- ^ options-      -> String -- ^ prog name-      -> String-usage sections pname =- let header   = "Usage: " ++ pname ++ " [OPTION...]\n"-     body     = unlines $ map usageSection sections- in header ++ body--usageSection :: (String, [OptDescr Flag],[String]) -> String-usageSection (name, opts, comments) =- usageInfo (unlines $ [bar,name, bar]) opts ++ mcomments- where-  bar = replicate 72 '='-  mcomments = if null comments then [] else "\n" ++ unlines comments--treatArgs :: [OptDescr Flag] -> [String] -> IO Params-treatArgs options argv = treatArgsWithParams options argv emptyParams--treatArgsWithParams :: [OptDescr Flag] -> [String] -> Params -> IO Params-treatArgsWithParams options argv initParams =-   case getOpt Permute options argv of-     (os,_,[]  )-> return $ defineParams os initParams-     (_,_,errs) -> do p <- getProgName-                      ioError (userError $ concat errs ++ usage basicSections p)--defineParams :: [Flag] -> Params -> Params-defineParams flgs prms =-  (\p -> foldr setDefault p $ geniFlags prms)-  . (mergeFlagsP OptimisationsFlg)-  . (mergeFlagsP MetricsFlg)-  $ prms-    { geniFlags     = flgs-    , builderType   = fromFlags builderType BuilderFlg flgs-    , grammarType   = fromFlags grammarType GrammarTypeFlg flgs-    }- where-  setDefault (Flag f v) p =-    if hasFlagP f p then p else setFlagP f v p-  mergeFlagsP f p =-    if hasFlagP f p-    then setFlagP f (concat $ getAllFlags f flgs) p-    else p-  fromFlags default_ t fs =-    fromMaybe (default_ prms) (getFlag t fs)-\end{code}--\section{Options by theme}-\label{sec:fancy_parameters}--At the time of this writing (2009-09-25), it is highly unlikely that all the-options are documented here.  See \verb!geni --help!  for more details.--Note that you might see an option described in more than one place-because it falls into multiple categories.--% ---------------------------------------------------------------------\subsection{Basic options}-% -----------------------------------------------------------------------\begin{code}-optionsForBasicStuff :: [OptDescr Flag]-optionsForBasicStuff =-  [ helpOption, verboseOption, noguiOption-  , macrosOption , lexiconOption, testSuiteOption-  , outputOption-  ]-\end{code}--% ---------------------------------------------------------------------\subsection{Input files}-% ----------------------------------------------------------------------See Chapter \ref{cha:formats} for details on how to write these files.--\begin{description}-\item[macros]-  The \verb!macros! switch is used to supply GenI with FB-LTAG tree-  schemata.-\item[lexicon]-  The \verb!lexicon! is used for lexical entries that point to the-  macros-\item[suite]-  The \verb!suite! provides test cases on which to run GenI-\item[ranking]-  The \verb!ranking! switch allows you to specify a file containing-  Optimality Theory style constraints which GenI will use to rank-  its output.  See Chapter \ref{cha:ranking} for more details on the format-  and use of this file.-\end{description}--\begin{code}-optionsForInputFiles :: [OptDescr Flag]-optionsForInputFiles =-  [ macrosOption-  , lexiconOption-  , tracesOption-  , testSuiteOption-  , fromStdinOption-  , morphInfoOption-  , instructionsOption-  , rankingOption-  , Option []    ["preselected"] (NoArg (Flag GrammarTypeFlg PreAnchored))-      "do NOT perform lexical selection - treat the grammar as the selection"-  ]--instructionsOption, macrosOption, lexiconOption, tracesOption :: OptDescr Flag--instructionsOption =-  Option [] ["instructions"] (reqArg InstructionsFileFlg id "FILE")-      "instructions file FILE"--macrosOption =-  Option ['m'] ["macros"] (reqArg MacrosFlg id "FILE")-      "tree schemata file FILE (unanchored trees)"--lexiconOption =-  Option ['l'] ["lexicon"] (reqArg LexiconFlg id "FILE")-     "lexicon file FILE"--tracesOption =-  Option [] ["traces"] (reqArg TracesFlg id "FILE")-    "traces file FILE (list of traces to display)"--rankingOption :: OptDescr Flag-rankingOption =-  Option [] ["ranking"] (reqArg RankingConstraintsFlg id "FILE")-    "ranking constraints FILE (using Optimality Theory)"-\end{code}--% ---------------------------------------------------------------------\subsection{Output}-% ----------------------------------------------------------------------\begin{code}-optionsForOutput :: [OptDescr Flag]-optionsForOutput =-  [ outputOption-  , Option []    ["dump"]    (noArg DumpDerivationFlg)-      "print derivation information on stdout (JSON)"-  , Option []    ["partial"] (noArg PartialFlg)-      "return partial result(s) if no complete solution is found"-  -- same as rankingOption but with output-centric help text-  , Option [] ["ranking"] (reqArg RankingConstraintsFlg id "FILE")-    "use constraints in FILE to rank output"-  ]--outputOption :: OptDescr Flag-outputOption =-  Option ['o'] ["output"] (reqArg OutputFileFlg id "FILE")-    "output file FILE (stdout if unset)"-\end{code}--% ---------------------------------------------------------------------\subsection{User interface}-% ----------------------------------------------------------------------\begin{code}-optionsForUserInterface :: [OptDescr Flag]-optionsForUserInterface =-  [ noguiOption, helpOption, versionOption-  , Option []    ["regression"] (noArg RegressionTestModeFlg)-      "Run in regression testing mode (needs grammar, etc)"-  , Option []    ["unit-tests"] (noArg RunUnitTestFlg)-      "Run in unit testing mode (no arguments needed)"-  , Option []    ["viewcmd"]  (reqArg ViewCmdFlg id "CMD")-      "XMG tree-view command"-  ]--noguiOption :: OptDescr Flag-noguiOption = Option [] ["nogui"] (noArg DisableGuiFlg)-                "disable graphical user interface"--helpOption :: OptDescr Flag-helpOption  = Option [] ["help"] (noArg HelpFlg)-                "show full list of command line switches"--versionOption :: OptDescr Flag-versionOption  = Option [] ["version"] (noArg VersionFlg)-                "display the version"--verboseOption :: OptDescr Flag-verboseOption = Option ['v'] ["verbose"] (noArg VerboseModeFlg)-                "verbose mode"-\end{code}--% ---------------------------------------------------------------------\subsection{Optimisations}-% ----------------------------------------------------------------------\begin{description}-\item[opt]-  The opt switch lets you specify a list of optimisations-  that GenI should use, for example, \texttt{--opt='pol S i'}.-  We associate each optimisation with a short code like 'i' for-  ``index accessibility filtering''.  This code is what the-  user passes in, and is sometimes used by GenI to tell the-  user which optimisations it's using.  See \texttt{geni-    --help} for more detail on the codes.--  Optimisations can be accumulated.  For example, if you say something-  like \texttt{--opt='foo bar' --opt='quux'} it is the same as saying-  \texttt{--opt='foo bar quux'}.--  Note that we also have two special thematic codes ``pol'' and-  ``adj'' which tell GenI that it should enable all the-  polarity-related, and all the adjunction-related-  optimisations respectively.--\item[detect-pols]-  This tells GenI how to detect polarities in your grammar.  You pass-  this in in the form of a space-delimited string, where each word is either-  an attribute or a ``restricted'' attribute.  In lieu of an explanation,-  here is an example: the string ``cat idx V.tense D.c'' tells GenI that-  we should detect polarities on the ``cat'' and ``idx'' attribute-  for all nodes and also on the ``tense'' attribute for all nodes-  with the category ``V'' and the ``c'' attribute for all nodes with the-  category ``D''.--  If your grammar comes with its own hand-written polarities, you can-  suppress polarity detection altogether by supplying the empty string.--  Also, if you do not use this switch, the following defaults will be-  used:--\begin{includecodeinmanual}-\begin{code}-defaultPolarityAttrs :: String-defaultPolarityAttrs = "cat"-\end{code}-\end{includecodeinmanual}--\item[rootfeat]-  No results?  Make sure your rootfeat are set correctly.  GenI-  will reject all sentences whose root category does not unify-  with the rootfeat, the default of which is:-\begin{includecodeinmanual}-\begin{code}-defaultRootFeat :: String-defaultRootFeat = "[cat:s inv:- mode:ind|subj wh:-]"-\end{code}-\end{includecodeinmanual}--  You can set rootfeat to be empty (\verb![]!) if you want, in-  which case the realiser proper will return all results; but-  note that if you want to use polarity filtering, you must at-  least specify a value for the \verb!cat! feature.--\item[extrapols]-  Allows to to preset some polarities.  There's not very much use for-  this, in my opinion.  Most likely, what you really want is rootfeat.-\end{description}--\begin{code}-optionsForOptimisation :: [OptDescr Flag]-optionsForOptimisation =-   [ Option [] ["opts"]-         (reqArg OptimisationsFlg readOptimisations "LIST")-         "optimisations 'LIST' (--help for details)"-   , Option [] ["detect-pols"]-         (reqArg DetectPolaritiesFlg readPolarityAttrs "LIST")-         ("attributes 'LIST' (eg. \"cat idx V.tense\", default:" ++ show defaultPolarityAttrs ++ ")")-   , Option [] ["rootfeat"]-         (reqArg RootFeatureFlg readRF "FEATURE")-         ("root features 'FEATURE' (for polarities, default:"-          ++ showFlist defaultRF ++ ")")-  , Option [] ["extrapols"]-         (reqArg ExtraPolaritiesFlg readPolarities "STRING")-         "preset polarities (normally, you should use rootfeat instead)"-  ]-  where-   defaultRF = getListFlagP RootFeatureFlg emptyParams-   readRF = parseFlagWithParsec "root feature" geniFeats-   readPolarities = parseFlagWithParsec "polarity string" geniPolarities--data Optimisation = PolOpts-                  | AdjOpts-                  | Polarised-                  | NoConstraints-                  | SemFiltered-                  | Iaf -- ^ one phase only!-                  | EarlyNa-  deriving (Show,Eq,Typeable)--coreOptimisationCodes :: [(Optimisation,String,String)]-coreOptimisationCodes =- [ (Polarised        , "p",      "polarity filtering")- , (EarlyNa          , "e-na",   "detect null adjunction at earliest opportunity")- , (SemFiltered      , "f-sem",  "semantic filtering (two-phase only)")- , (Iaf              , "i",      "index accesibility filtering (one-phase only)")- , (NoConstraints    , "nc",     "disable semantic constraints (anti-optimisation!)")- ]--optimisationCodes :: [(Optimisation,String,String)]-optimisationCodes =- coreOptimisationCodes ++- [ (SemFiltered      , "S",      "semantic filtering (same as f-sem)")- , (PolOpts          , "pol",    equivalentTo polOpts)- , (AdjOpts          , "adj",    equivalentTo adjOpts)- ]- where equivalentTo os = "equivalent to '" ++ (unwords $ map showOptCode os) ++ "'"--polOpts, adjOpts :: [Optimisation]-polOpts = [Polarised]-adjOpts = [EarlyNa, SemFiltered]-\end{code}--\begin{code}--- ------------------------------------------------------------------------ Optimisation usage info--- -----------------------------------------------------------------------lookupOpt:: Optimisation -> (String, String)-lookupOpt k =- case find (\x -> k == fst3 x) optimisationCodes of- Just (_, c, d) -> (c, d)- Nothing -> geniBug $ "optimisation " ++  show k ++ " unknown"--showOptCode :: Optimisation -> String-showOptCode = fst.lookupOpt--describeOpt :: (Optimisation, String, String) -> String-describeOpt (_,k,d) = k ++ " - " ++ d---- | Displays the usage text for optimisations.---   It shows a table of optimisation codes and their meaning.-usageForOptimisations :: [String]-usageForOptimisations =-     [ "Optimisations must be passed in as a space-delimited list"-     , "(ex: --opt='p f-sem' for polarities and semantic filtering)"-     , ""-     , "Optimisations:"-     , "  " ++ unlinesTab (map describeOpt coreOptimisationCodes)-     ]- where unlinesTab l = concat (intersperse "\n  " l)-\end{code}--\begin{code}--- ------------------------------------------------------------------------ Parsing optimisation stuff--- ------------------------------------------------------------------------- | If we do not recognise a code, we output an error message.  We---  also take the liberty of expanding thematic codes like 'pol'---  into the respective list of optimisations.-readOptimisations :: String -> [Optimisation]-readOptimisations str =-  case parseOptimisations str of-    Left ick -> error $ "Unknown optimisations: " ++ (unwords ick)-    Right os -> (addif PolOpts polOpts) . (addif AdjOpts adjOpts) $ os-  where addif t x o = if (t `elem` o) then x ++ o else o---- | Returns |Left| for any codes we don't recognise, or---   |Right| if everything is ok.-parseOptimisations :: String -> Either [String] [Optimisation]-parseOptimisations str =-  let codes = words str-      mopts = map lookupOptimisation codes-  in if any isNothing mopts-     then Left  [ c | (c,o) <- zip codes mopts, isNothing o ]-     else Right $ map fromJust mopts--lookupOptimisation :: String -> Maybe Optimisation-lookupOptimisation code =-  liftM fst3 $ find (\x -> snd3 x == code) optimisationCodes--parseFlagWithParsec :: String -> CharParser () b -> String -> b-parseFlagWithParsec description p str =- case runParser p () "" str of- Left  err -> error $ "Couldn't parse " ++ description ++ " because " ++ show err- Right res -> res-\end{code}--% ---------------------------------------------------------------------\subsection{Builders}-% ----------------------------------------------------------------------\begin{description}-\item[builder]-  A builder is basically a surface realisation algorithm.  \geni has the-  infrastructure to support different realisation algorithms, but some-  broken ones have been removed.-\end{description}--\begin{code}-data BuilderType = NullBuilder |-                   SimpleBuilder | SimpleOnePhaseBuilder-     deriving (Eq, Typeable)--instance Show BuilderType where-  show NullBuilder           = "null"-  show SimpleBuilder         = "simple-2p"-  show SimpleOnePhaseBuilder = "simple-1p"--optionsForBuilder :: [OptDescr Flag]-optionsForBuilder =-  [ Option ['b'] ["builder"]  (reqArg BuilderFlg readBuilderType "BUILDER")-      ("use as realisation engine one of: " ++ (unwords $ map show mainBuilderTypes))-  ]--mainBuilderTypes :: [BuilderType]-mainBuilderTypes =- [ SimpleBuilder, SimpleOnePhaseBuilder- ]---- | Hint: compose with (map toLower) to make it case-insensitive-mReadBuilderType :: String -> Maybe BuilderType-mReadBuilderType "null"      = Just NullBuilder-mReadBuilderType "simple"    = Just SimpleBuilder-mReadBuilderType "simple-2p" = Just SimpleBuilder-mReadBuilderType "simple-1p" = Just SimpleOnePhaseBuilder-mReadBuilderType _           = Nothing---- | Is case-insensitive, error if unknown type-readBuilderType :: String -> BuilderType-readBuilderType b =-  case mReadBuilderType $ map toLower b of-  Just x  -> x-  Nothing -> error $ "Unknown builder type " ++ b--\end{code}--% ---------------------------------------------------------------------\subsection{Testing and profiling}-% ----------------------------------------------------------------------\begin{code}-fromStdinOption :: OptDescr Flag-fromStdinOption =-  Option [] ["from-stdin"] (noArg FromStdinFlg) "get testcase from stdin"--testSuiteOption :: OptDescr Flag-testSuiteOption =-  Option ['s'] ["testsuite"] (reqArg TestSuiteFlg id "FILE") "test suite FILE"--optionsForTesting :: [OptDescr Flag]-optionsForTesting =-  [ testSuiteOption-  , fromStdinOption-  , Option []    ["testcase"]   (reqArg TestCaseFlg id "STRING")-      "run test case STRING"-  , Option []    ["timeout"] (reqArg TimeoutFlg read "SECONDS")-      "time out after SECONDS seconds"-  , Option []    ["metrics"] (optArg MetricsFlg ["default"] words "LIST")-      "keep track of performance metrics: (default: iterations comparisons chart_size)"-  , Option []    ["statsfile"] (reqArg StatsFileFlg id "FILE")-      "write performance data to file FILE (stdout if unset)"-  , Option []    ["batchdir"]    (reqArg BatchDirFlg id "DIR")-      "batch process the test suite and save results to DIR"-  , Option []    ["earlydeath"]    (noArg EarlyDeathFlg)-      "exit on first case with no results (batch processing) "- ]-\end{code}--% ---------------------------------------------------------------------\subsection{Morphology}-% ----------------------------------------------------------------------GenI provides two options for morphology: either you use an external-inflection program (morphcmd), or you pass in a morphological lexicon-(morphlexicon) and in doing so, use GenI's built in inflecter.  The-GenI internal morphology mechanism is a simple and stupid lookup-and--unify table, so you probably don't want to use it if you have a huge-lexicon.--\begin{description}-\item[morphcmd] specifies the program used for morphology.  Literate-GenI \cite{literateGeni} has a chapter describing how that program must work.-It will mostly likely be a script you wrote to wrap around some off-the-shelf-software.-\item[morphlexicon] specifies a morphological lexicon for use by-GenI's internal morphological generator.  Specifying this option will-cause the morphcmd flag to be ignored.-\item[morphinfo] tells GenI which literals in the input semantics are-to be used by the morphological \emph{pre-}processor.  The pre-processor-strips these features from the input and fiddles with the elementary-trees used by GenI so that the right features get attached to the leaf-nodes.  An example of a ``morphological'' literal is something like-\texttt{past(p)}.-\end{description}--\begin{code}-optionsForMorphology :: [OptDescr Flag]-optionsForMorphology =-  [ morphInfoOption-  , Option []    ["morphcmd"]  (reqArg MorphCmdFlg id "CMD")-      "morphological post-processor CMD (default: unset)"-  ]--morphInfoOption :: OptDescr Flag-morphInfoOption = Option [] ["morphinfo"] (reqArg MorphInfoFlg id "FILE")-  "morphological features FILE (default: unset)"-\end{code}--% ---------------------------------------------------------------------\subsection{Other options}-% ----------------------------------------------------------------------\begin{code}-data GrammarType = GeniHand    -- ^ geni's text format-                 | PreCompiled -- ^ built into geni, no parsing needed-                 | PreAnchored -- ^ lexical selection already done-     deriving (Show, Eq, Typeable)-\end{code}--% ====================================================================-\section{Scripting GenI}-% ====================================================================--\begin{description}-\item[instructions] An instructions file can be used to run GenI on-a list of test suites and cases.--Any input that you give to GenI will be interpreted as a list of test-suites (and test cases that you want to run).  Each line has the format-\texttt{path/to/test-suite case1 case2 .. caseN}.   You can omit the-test cases, which is interpreted as you wanting to run the entire test-suite.  Also, the \verb!%! character and anything after is treated as-a comment.--Interaction with \verb!--testsuite! and \verb!--testcase!:-\begin{itemize}-\item If only \verb!--instructions! is set, then the first test suite-      and or test case from the instructions file is used.-\item If only \verb!--testsuite! and \verb!--testcase! are set, we-      pretend that an instructions file was supplied saying that we-      want to run the entirety of the test suite specified in-      \verb!--testsuite!.-\item If both \verb!--instructions! and \verb!--testsuite!/-      \verb!--testcase! are set then the latter are used to-      select from within the instructions.-\end{itemize}-\end{description}---\begin{code}-type Instruction = (FilePath, Maybe [String])---- | Update the internal instructions list, test suite and case---   according to the contents of an instructions file.-processInstructions :: Params -> IO Params-processInstructions config =- do instructions <- case getFlagP InstructionsFileFlg config of-                      Nothing -> return fakeInstructions-                      Just f  -> instructionsFile `fmap` readFile f-    -- basically set the test suite/case flag to the first instruction-    -- note that with the above code (which sets the first instruction-    -- to the test suite/case flag), this should work out to identity-    -- when those flags are provided.-    let updateInstructions =-          setFlagP TestInstructionsFlg instructions-        updateTestCase p =-          if hasFlagP TestCaseFlg p then p-             else case (listToMaybe instructions >>= snd >>= listToMaybe) of-                   Just c   -> setFlagP TestCaseFlg c p -                   Nothing  -> p-        updateTestSuite p =-          if hasFlagP TestSuiteFlg p then p-             else case (fst `fmap` listToMaybe instructions) of-                   Just s  -> setFlagP TestSuiteFlg s p-                   Nothing -> p-    return . updateInstructions . updateTestSuite . updateTestCase $ config- where-  fakeInstructions =-     case getFlagP TestSuiteFlg config of-       Just ts -> [ (ts, Nothing) ]-       Nothing -> []--instructionsFile :: String -> [Instruction]-instructionsFile = mapMaybe inst . lines- where-  inst l = case words (takeWhile (/= '%') l) of-           []     -> Nothing-           [f]    -> Just (f, Nothing)-           (f:cs) -> Just (f, Just cs)-\end{code}--% ====================================================================-% Flags-% ====================================================================--\begin{code}-{--Flags are GenI's internal representation of command line arguments.  We-use phantom existential types (?) for representing GenI flags.  This-makes it simpler to do things such as ``get the value of the MacrosFlg''-whilst preserving type safety (we always know that MacrosFlg is-associated with String).  The alternative would be writing getters and-setters for each flag, and that gets really boring after a while.--}--data Flag = forall f x . (Eq f, Show f, Show x, Typeable f, Typeable x) =>-     Flag (x -> f) x deriving (Typeable)--instance Show Flag where- show (Flag f x) = "Flag " ++ show (f x)--instance Eq Flag where- (Flag f1 x1) == (Flag f2 x2)-   | (typeOf f1 == typeOf f2) && (typeOf x1 == typeOf x2) =-       (fromJust . cast . f1 $ x1) == (f2 x2)-   | otherwise = False--isFlag     :: (Typeable f, Typeable x) => (x -> f) -> Flag -> Bool-hasFlag    :: (Typeable f, Typeable x) => (x -> f) -> [Flag] -> Bool-deleteFlag :: (Typeable f, Typeable x) => (x -> f) -> [Flag] -> [Flag]-setFlag    :: (Eq f, Show f, Show x, Typeable f, Typeable x) => (x -> f) -> x -> [Flag] -> [Flag]-getFlag    :: (Show f, Show x, Typeable f, Typeable x)  => (x -> f) -> [Flag] -> Maybe x-getAllFlags :: (Show f, Show x, Typeable f, Typeable x) => (x -> f) -> [Flag] -> [x]--isFlag f1 (Flag f2 _) = typeOf f1 == typeOf f2-hasFlag f       = any (isFlag f)-deleteFlag f    = filter (not.(isFlag f))-setFlag f v fs  = (Flag f v) : tl where tl = deleteFlag f fs-getFlag f fs    = do (Flag _ v) <- find (isFlag f) fs ; cast v-getAllFlags f fs = catMaybes [ cast v | flg@(Flag _ v) <- fs, isFlag f flg ]---{--Below are just the individual flags, which unfortunately have to be-defined as separate data types because of our fancy existential-data type code.--}--- input files-#define FLAG(x,y) data x = x y deriving (Eq, Show, Typeable)--FLAG (BatchDirFlg, FilePath)-FLAG (DisableGuiFlg, ())-FLAG (DetectPolaritiesFlg, (Set.Set PolarityAttr))-FLAG (DumpDerivationFlg, ())-FLAG (EarlyDeathFlg, ())-FLAG (ExtraPolaritiesFlg, (Map.Map PolarityKey Interval))-FLAG (FromStdinFlg, ())-FLAG (HelpFlg, ())-FLAG (InstructionsFileFlg, FilePath)-FLAG (LexiconFlg, FilePath)-FLAG (MacrosFlg, FilePath)-FLAG (TracesFlg, FilePath)-FLAG (MetricsFlg, [String])-FLAG (MorphCmdFlg, String)-FLAG (MorphInfoFlg, FilePath)-FLAG (OptimisationsFlg, [Optimisation])-FLAG (OutputFileFlg, String)-FLAG (PartialFlg, ())-FLAG (RankingConstraintsFlg, FilePath)-FLAG (RegressionTestModeFlg, ())-FLAG (RootFeatureFlg, Flist)-FLAG (RunUnitTestFlg, ())-FLAG (NoLoadTestSuiteFlg, ())-FLAG (StatsFileFlg, FilePath)-FLAG (TestCaseFlg, String)-FLAG (TestInstructionsFlg, [Instruction])-FLAG (TestSuiteFlg, FilePath)-FLAG (TimeoutFlg, Integer)-FLAG (VerboseModeFlg, ())-FLAG (VersionFlg, ())-FLAG (ViewCmdFlg, String)--- not to be exported (defaults)--- the WeirdFlg exists strictly to please OS X when you launch--- GenI in an application bundle (double-click)... for some--- reason it wants to pass an argument to -p-FLAG (BuilderFlg,  BuilderType)-FLAG (GrammarTypeFlg, GrammarType)-FLAG (WeirdFlg, String)-\end{code}--
src/NLP/GenI/Console.hs view
@@ -18,51 +18,98 @@ -- | The console user interface including batch processing on entire --   test suites. -module NLP.GenI.Console(consoleGeni, runTestCaseOnly) where+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE PatternGuards #-}+{-# LANGUAGE OverloadedStrings #-}+module NLP.GenI.Console ( consoleGeni, loadNextSuite ) where +import Control.Applicative ( pure, (<$>) ) import Control.Monad import Data.IORef(readIORef, modifyIORef)-import Data.List(find, sort)-import Data.Maybe ( isJust, fromMaybe )-import System.Directory(createDirectoryIfMissing)-import System.Exit ( exitFailure )+import Data.List ( find, partition )+import Data.Maybe ( fromMaybe, isJust )+import Data.Text ( Text )+import Data.Time ( getCurrentTime, formatTime )+import Data.Typeable+import System.Log.Logger+import System.Locale ( defaultTimeLocale, iso8601DateFormat )+import System.Directory( createDirectoryIfMissing, getTemporaryDirectory )+import System.Exit ( exitWith, exitFailure, ExitCode(..) ) import System.FilePath ( (</>), takeFileName )+import System.IO ( stderr )+import System.Timeout ( timeout )+import qualified Data.ByteString as B+import qualified Data.Text as T+import qualified Data.Text.IO as T+import qualified Data.Text.Encoding as T -import NLP.GenI.Btypes-   ( SemInput, TestCase(tcSem, tcName)-   )-import qualified NLP.GenI.Btypes as G+ import NLP.GenI.General-  ( ePutStr, ePutStrLn, withTimeout, exitTimeout+  ( ePutStr, ePutStrLn,   )-import NLP.GenI.Geni+import NLP.GenI import NLP.GenI.Configuration   ( Params-  , BatchDirFlg(..), DumpDerivationFlg(..), EarlyDeathFlg(..), FromStdinFlg(..), OutputFileFlg(..)-  , MetricsFlg(..), RankingConstraintsFlg(..), StatsFileFlg(..)+  , BatchDirFlg(..), DumpDerivationFlg(..), EarlyDeathFlg(..)+  , MetricsFlg(..), RankingConstraintsFlg(..)   , TestCaseFlg(..), TestSuiteFlg(..), TestInstructionsFlg(..)+  , FromStdinFlg(..), OutputFileFlg(..), StatsFileFlg(..)   , TimeoutFlg(..),  VerboseModeFlg(..)   , hasFlagP, getListFlagP, getFlagP, setFlagP   , builderType , BuilderType(..)   )-import qualified NLP.GenI.Builder as B+import NLP.GenI.General ( mkLogname )+import NLP.GenI.Pretty+import NLP.GenI.Semantics ( SemInput ) import NLP.GenI.Simple.SimpleBuilder-import NLP.GenI.Statistics ( Statistics )+import NLP.GenI.TestSuite ( TestCase(..) )  import Text.JSON import Text.JSON.Pretty ( render, pp_value )  consoleGeni :: ProgStateRef -> IO() consoleGeni pstRef = do-  pst <- readIORef pstRef-  loadEverything pstRef-  case getFlagP TimeoutFlg (pa pst) of-    Nothing -> runInstructions pstRef-    Just t  -> withTimeout t (timeoutErr t) $ runInstructions pstRef-  where-   timeoutErr t = do ePutStrLn $ "GenI timed out after " ++ (show t) ++ "s"-                     exitTimeout+    config <- pa <$> readIORef pstRef+    loadEverything pstRef+    let job | hasFlagP FromStdinFlg config           = runStdinTestCase pstRef+            | hasFlagP BatchDirFlg config            = runInstructions pstRef -- even if there is a testcase+            | Just tc <- getFlagP TestCaseFlg config = runSpecificTestCase pstRef tc+            | otherwise                              = runInstructions pstRef+    case getFlagP TimeoutFlg config of+      Nothing -> job+      Just t  -> withGeniTimeOut t job +withGeniTimeOut :: Int -- ^ seconds+                -> IO ()+                -> IO ()+withGeniTimeOut t job = do+    status <- timeout (fromIntegral t * 1000000) job+    case status of+      Just () -> return ()+      Nothing -> do+          ePutStrLn $ "GenI timed out after " ++ show t ++ "s"+          exitWith (ExitFailure 2)++-- | Run GenI without reading any test suites, just grab semantics from stdin+runStdinTestCase :: ProgStateRef -> IO ()+runStdinTestCase pstRef = do+    config   <- pa <$> readIORef pstRef+    mSemInput <- parseSemInput <$> getContents+    case mSemInput of+      Left err ->+           fail $ "I didn't understand the semantics you gave me: " ++ show err+      Right semInput ->+           runOnSemInput pstRef (runAsStandalone config) semInput >> return ()++-- | Run a test case with the specified name+runSpecificTestCase :: ProgStateRef -> Text -> IO ()+runSpecificTestCase pstRef cname = do+    config <- pa <$> readIORef pstRef+    fullsuite <- loadTestSuite pstRef+    case find (\x -> tcName x == cname) fullsuite  of+        Nothing -> fail ("No such test case: " ++ T.unpack cname)+        Just s  -> runOnSemInput pstRef (runAsStandalone config) (tcSem s) >> return ()+ -- | Runs the tests specified in our instructions list. --   We assume that the grammar and lexicon are already --   loaded into the monadic state.@@ -72,123 +119,165 @@ runInstructions pstRef =   do pst <- readIORef pstRef      let config = pa pst-     case getFlagP BatchDirFlg config of-       Nothing   -> runTestCaseOnly pstRef >> return ()-       Just bdir -> runBatch bdir+     batchDir <- case getFlagP BatchDirFlg config of+                   Nothing  -> do+                     t   <- getTemporaryDirectory+                     utc <- fmtTime <$> getCurrentTime+                     return (t </> "geni-" ++ utc)+                   Just bdir -> return bdir+     runBatch batchDir+     unless (hasFlagP BatchDirFlg config) $ do+       ePutStr $ unlines [ ""+                         , "Results saved to directory " ++ batchDir+                         , "To save results in a different directory, use the --batchdir flag"+                         ]   where-  runBatch bdir =-    do config <- pa `fmap` readIORef pstRef-       mapM_ (runSuite bdir) $ getListFlagP TestInstructionsFlg config-  runSuite bdir (file, mtcs) =-    do modifyIORef pstRef $ \p -> p { pa = setFlagP TestSuiteFlg file (pa p) }-       config <- pa `fmap` readIORef pstRef+  fmtTime = formatTime defaultTimeLocale (iso8601DateFormat (Just "%H%M"))+  runBatch bdir = do+      config <- pa <$> readIORef pstRef+      mapM_ (runSuite bdir) $+          getListFlagP TestInstructionsFlg config+  runSuite bdir next@(file, _) =+    do suite  <- loadNextSuite pstRef next        -- we assume the that the suites have unique filenames        let bsubdir = bdir </> takeFileName file-       createDirectoryIfMissing False bsubdir-       fullsuite <- loadTestSuite pstRef-       let suite = case (mtcs, getFlagP TestCaseFlg config) of-                    (_, Just c) -> filter (\t -> tcName t == c) fullsuite-                    (Nothing,_) -> fullsuite-                    (Just cs,_) -> filter (\t -> tcName t `elem` cs) fullsuite-       if any null $ map tcName suite+       createDirectoryIfMissing True bsubdir+       if any (T.null . tcName) suite           then    fail $ "Can't do batch processing. The test suite " ++ file ++ " has cases with no name."           else do ePutStrLn "Batch processing mode"                   mapM_ (runCase bsubdir) suite-  runCase bdir (G.TestCase { tcName = n, tcSem = s }) =+  runCase bdir (TestCase { tcName = n, tcSem = s }) =    do config <- pa `fmap` readIORef pstRef       let verbose = hasFlagP VerboseModeFlg config           earlyDeath = hasFlagP EarlyDeathFlg config       when verbose $         ePutStrLn "======================================================"-      (res , _) <- runOnSemInput pstRef (PartOfSuite n bdir) s-      ePutStrLn $ " " ++ n ++ " - " ++ (show $ length res) ++ " results"+      gresults <- runOnSemInput pstRef (PartOfSuite n bdir) s+      let res = grResults gresults+          (goodres, badres) = partition isSuccess (grResults gresults)+      T.hPutStrLn stderr $+          " " <> n <+> "-" <+> pretty (length goodres) <+> "results" <+>+          parens (pretty (length badres))       when (null res && earlyDeath) $ do-        ePutStrLn $ "Exiting early because test case " ++ n ++ " failed."-        exitFailure+          T.hPutStrLn stderr $ "Exiting early because test case" <+> n <+> "failed."+          exitFailure --- | Run the specified test case, or failing that, the first test---   case in the suite-runTestCaseOnly :: ProgStateRef -> IO ([GeniResult], Statistics)-runTestCaseOnly pstRef =- do pst <- readIORef pstRef-    let config     = pa pst-        pstOutfile = fromMaybe "" $ getFlagP OutputFileFlg config-        sFile      = fromMaybe "" $ getFlagP StatsFileFlg  config-    semInput <- case getFlagP TestCaseFlg config of-                   Nothing -> if hasFlagP FromStdinFlg config-                                 then do getContents >>= loadTargetSemStr pstRef-                                         ts `fmap` readIORef pstRef-                                 else getFirstCase pst-                   Just c  -> findCase pst c-    runOnSemInput pstRef (Standalone pstOutfile sFile) semInput- where-  getFirstCase pst =-    case tsuite pst of-    []    -> fail "Test suite is empty."-    (c:_) -> return $ tcSem c-  findCase pst theCase =-    case find (\x -> tcName x == theCase) (tsuite pst) of-    Nothing -> fail ("No such test case: " ++ theCase)-    Just s  -> return $ tcSem s+-- | Used in processing instructions files. Each instruction consists of a+--   suite file and a list of test case names from that file+--+--   See <http://projects.haskell.org/GenI/manual/command-line.html> for+--   how testsuite, testcase, and instructions are expected to interact+--+--   (Exported for use by regression testing code)+loadNextSuite :: ProgStateRef -> (FilePath, Maybe [Text]) -> IO [TestCase]+loadNextSuite pstRef (file, mtcs) = do+    debugM logname $ "Loading next test suite: " ++ file+    debugM logname $ "Test case filter: " ++ maybe "none" (\xs -> show (length xs) ++ " items") mtcs+    modifyIORef pstRef $ \p -> p { pa = setFlagP TestSuiteFlg file (pa p) } -- yucky statefulness! :-(+    config <- pa `fmap` readIORef pstRef+    let mspecific = getFlagP TestCaseFlg config+    debugM logname . T.unpack $ "Test case to pick out:" <+> fromMaybe "none"  mspecific+    fullsuite <- loadTestSuite pstRef+    return (filterSuite mtcs mspecific fullsuite)+  where+    filterSuite _         (Just c) suite = filter (\t -> tcName t == c) suite+    filterSuite Nothing   Nothing  suite = suite+    filterSuite (Just cs) Nothing  suite = filter (\t -> tcName t `elem` cs) suite  data RunAs = Standalone  FilePath FilePath-           | PartOfSuite String FilePath+           | PartOfSuite Text FilePath +runAsStandalone :: Params -> RunAs+runAsStandalone config =+    Standalone (fromMaybe "" $ getFlagP OutputFileFlg config)+               (fromMaybe "" $ getFlagP StatsFileFlg config)+ -- | Runs a case in the test suite.  If the user does not specify any test --   cases, we run the first one.  If the user specifies a non-existing --   test case we raise an error. runOnSemInput :: ProgStateRef               -> RunAs               -> SemInput-              -> IO ([GeniResult], Statistics)-runOnSemInput pstRef args semInput =-  do modifyIORef pstRef (\x -> x{ts = semInput, warnings = []})-     pst <- readIORef pstRef-     let config = pa pst-         dump = hasFlagP DumpDerivationFlg config-         useRanking = hasFlagP RankingConstraintsFlg config-     (results, stats) <- case builderType config of-                            NullBuilder   -> helper B.nullBuilder-                            SimpleBuilder -> helper simpleBuilder_2p-                            SimpleOnePhaseBuilder -> helper simpleBuilder_1p-     warningsOut <- warnings `fmap` readIORef pstRef-     -- create directory if need be-     case args of-       PartOfSuite n f -> createDirectoryIfMissing False (f </> n)-       _               -> return ()-     let oWrite = case args of-                     Standalone "" _ -> putStrLn-                     Standalone f  _ -> writeFile f-                     PartOfSuite n f -> writeFile $ f </> n </> "responses"-         doWrite = case args of-                     Standalone _  _ -> const (return ())-                     PartOfSuite n f -> writeFile $ f </> n </> "derivations"-         soWrite = case args of-                     Standalone _ "" -> putStrLn-                     Standalone _ f  -> writeFile f-                     PartOfSuite n f -> writeFile $ f </> n </> "stats"-     ---     if dump-        then oWrite . ppJSON $ results-        else if useRanking-                then oWrite . unlines . map (prettyResult pst) $ results-                else oWrite . unlines . sort . concatMap grRealisations $ results-     doWrite . ppJSON $ results-     -- print any warnings we picked up along the way-     when (not $ null warningsOut) $-      do let ws = reverse warningsOut-         ePutStr $ "Warnings:\n" ++ (unlines $ map (\x -> " - " ++ x) ws)-         case args of-          PartOfSuite n f -> writeFile (f </> n </> "warnings") $ unlines ws-          _ -> return ()-     -- print out statistical data (if available)-     when (isJust $ getFlagP MetricsFlg config) $ soWrite (ppJSON stats)-     ---     return (results, stats)+              -> IO GeniResults+runOnSemInput pstRef args semInput = do+    pst <- readIORef pstRef+    case builderType (pa pst) of+             SimpleBuilder         -> helper pst simpleBuilder_2p+             SimpleOnePhaseBuilder -> helper pst simpleBuilder_1p   where-    ppJSON :: JSON a => a -> String-    ppJSON = render . pp_value . showJSON -    helper builder =-      do (results, stats, _) <- runGeni pstRef builder-         return (results, stats)+    helper pst builder = do+         (res,_) <- runGeni pstRef semInput builder+         writeResults pst args semInput res+         return res +-- | Not just the global warnings but the ones local to each response too+allWarnings :: GeniResults -> [Text]+allWarnings res = concat $ grGlobalWarnings res+                         : [ grWarnings s | GSuccess s <- grResults res ]++writeResults :: ProgState -> RunAs -> SemInput -> GeniResults -> IO ()+writeResults pst args semInput gresults = do+    -- create output directory as needed+    case args of+        PartOfSuite n f -> createDirectoryIfMissing True (f </> T.unpack n)+        _               -> return ()+    -- print responses+    if dump+       then writeResponses $ ppJSON results+       else writeResponses $ T.unlines . concatMap (fromResult formatResponses) $ results+    -- print out statistical data (if available)+    when (isJust $ getFlagP MetricsFlg config) $+       writeStats (ppJSON stats)+    -- print any warnings we picked up along the way+    unless (null warnings) $ do+       T.hPutStrLn stderr $ "Warnings:\n" <> formatWarnings warnings+       writeBatchFile "warnings" $ T.unlines warnings+    -- other outputs when run in batch mode+    writeBatchFile "semantics"  $ pretty semInput+    writeBatchFile "derivations"$ ppJSON results+  where+    results     = grResults    gresults+    warnings    = allWarnings  gresults+    stats       = grStatistics gresults+    config      = pa pst+    dump        = hasFlagP DumpDerivationFlg config+    -- do we print ranking information and all that other jazz?+    formatResponses = if hasFlagP RankingConstraintsFlg config+                         then pure . prettyResult pst+                         else grRealisations+    formatWarnings = T.unlines . map (" - " <>)+    --+    writeBatchFile key = case args of+        Standalone _  _ -> const (return ())+        PartOfSuite n f -> writeFileUtf8 (f </> T.unpack n </> key)+    writeResponses = case args of+        Standalone "" _ -> putStrLnUtf8+        Standalone f  _ -> writeFileUtf8 f+        PartOfSuite _ _ -> writeBatchFile "responses"+    writeStats = case args of+        Standalone _ "" -> putStrLnUtf8+        Standalone _ f  -> writeFileUtf8 f+        PartOfSuite _ _ -> writeBatchFile "stats"+    --+    fromResult :: (GeniSuccess -> [Text]) -> GeniResult -> [Text]+    fromResult _ (GError errs) = [ pretty errs ]+    fromResult f (GSuccess x)  = f x++-- | TODO: If somebody puts together a render function that emits Data.Text+--   we should just use that instead+ppJSON :: JSON a => a -> Text+ppJSON = T.pack . render . pp_value . showJSON++writeFileUtf8 :: FilePath -> Text -> IO ()+writeFileUtf8 f = B.writeFile f . T.encodeUtf8++putStrLnUtf8 :: Text -> IO ()+putStrLnUtf8 = B.putStr . T.encodeUtf8 . (<> "\n")++-- ----------------------------------------------------------------------+-- Odds and ends+-- ----------------------------------------------------------------------++data MNAME = MNAME deriving Typeable+logname :: String+logname = mkLogname MNAME
+ src/NLP/GenI/FeatureStructure.hs view
@@ -0,0 +1,186 @@+-- GenI surface realiser+-- Copyright (C) 2005-2009 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.++{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE FlexibleInstances, TypeSynonymInstances, MultiParamTypeClasses #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE OverloadedStrings #-}+module NLP.GenI.FeatureStructure where++import Data.Binary+import Data.Function (on)+import Data.Generics (Data)+import Data.List (sortBy)+import qualified Data.Map as Map+import Data.Typeable (Typeable)+import Data.Text ( Text )+import qualified Data.Text as T++import NLP.GenI.GeniShow+import NLP.GenI.GeniVal+import NLP.GenI.General ( geniBug )+import NLP.GenI.Pretty++import Control.DeepSeq++-- ----------------------------------------------------------------------+-- Core types+-- ----------------------------------------------------------------------++type Flist a  = [AvPair a]+data AvPair a = AvPair { avAtt :: Text+                       , avVal :: a }+  deriving (Ord, Eq, Data, Typeable)++-- experimental, alternative representation of Flist+-- which guarantees uniqueness of keys+type FeatStruct a = Map.Map Text a++emptyFeatStruct :: FeatStruct a+emptyFeatStruct = Map.empty++mkFeatStruct :: Flist GeniVal -> FeatStruct GeniVal +mkFeatStruct fs = Map.fromListWith oops . map fromPair $ fs+  where+   fromPair (AvPair a v) = (a,v)+   oops _ _ = geniBug $+     "I've allowed a feature structure with multiple versions of a key"+     ++ " to sneak through: " ++ prettyStr fs++fromFeatStruct :: FeatStruct a -> Flist a+fromFeatStruct = sortFlist . map (uncurry AvPair) . Map.toList++-- if we decide to move over to this representation of feature structures+-- we can get rid of showFlist, etc and probably just use toAscList+instance Pretty (FeatStruct GeniVal) where+    pretty = pretty . fromFeatStruct++instance GeniShow (FeatStruct GeniVal) where+    geniShowText = geniShowText . fromFeatStruct++-- ----------------------------------------------------------------------+-- Basic functions+-- ----------------------------------------------------------------------++-- | Sort an Flist according with its attributes+sortFlist :: Flist a -> Flist a+sortFlist = sortBy (compare `on` avAtt)++-- Traversal++instance DescendGeniVal v => DescendGeniVal (AvPair v) where+  descendGeniVal s (AvPair a v) = {-# SCC "descendGeniVal" #-} AvPair a (descendGeniVal s v)++instance DescendGeniVal a => DescendGeniVal (String, a) where+  descendGeniVal s (n,v) = {-# SCC "descendGeniVal" #-} (n,descendGeniVal s v)++instance DescendGeniVal v => DescendGeniVal ([String], Flist v) where+  descendGeniVal s (a,v) = {-# SCC "descendGeniVal" #-} (a, descendGeniVal s v)++instance Collectable a => Collectable (AvPair a) where+  collect (AvPair _ b) = collect b++-- Pretty printing and output format++instance Pretty (Flist GeniVal) where+    pretty = geniShowText++instance Pretty (AvPair GeniVal) where+    pretty = geniShowText++instance GeniShow (Flist GeniVal) where+    geniShowText = squares . T.unwords . map geniShowText++instance GeniShow (AvPair GeniVal) where+    geniShowText (AvPair a v) = a `T.append` ":" `T.append` geniShowText v++{-+instance Show (AvPair GeniVal) where+  show = showAv+-}++-- --------------------------------------------------------------------+-- Feature structure unification+-- --------------------------------------------------------------------++-- | 'unifyFeat' performs feature structure unification, under the+--   these assumptions about the input:+--+--    * Features are ordered+--+--    * The Flists do not share variables (renaming has already+--      been done.+--+--   The features are allowed to have different sets of attributes,+--   beacuse we use 'alignFeat' to realign them.+unifyFeat :: Monad m => Flist GeniVal -> Flist GeniVal -> m (Flist GeniVal, Subst)+unifyFeat f1 f2 =+  {-# SCC "unification" #-}+  let (att, val1, val2) = unzip3 $ alignFeat f1 f2+  in att `seq`+     do (res, subst) <- unify val1 val2+        return (zipWith AvPair att res, subst)++-- | 'alignFeat' is a pre-procesing step used to ensure that feature structures+--   have the same set of keys.  If a key is missing in one, we copy it to the+--   other with an anonymous value.+--+--   The two feature structures must be sorted for this to work+alignFeat :: Flist GeniVal -> Flist GeniVal -> [(Text,GeniVal,GeniVal)]+alignFeat f1 f2 = alignFeatH f1 f2 []++alignFeatH :: Flist GeniVal -> Flist GeniVal -> [(Text,GeniVal,GeniVal)] -> [(Text,GeniVal,GeniVal)]+alignFeatH [] [] acc = reverse acc+alignFeatH [] (AvPair f v :x) acc = alignFeatH [] x ((f,mkGAnon,v) : acc)+alignFeatH x [] acc = alignFeatH [] x acc+alignFeatH fs1@(AvPair f1 v1:l1) fs2@(AvPair f2 v2:l2) acc =+   case compare f1 f2 of+     EQ -> alignFeatH l1 l2  ((f1, v1, v2) : acc)+     LT -> alignFeatH l1 fs2 ((f1, v1, mkGAnon) : acc)+     GT -> alignFeatH fs1 l2 ((f2, mkGAnon, v2) : acc)++-- --------------------------------------------------------------------+-- Fancy disjunction+-- --------------------------------------------------------------------++crushAvPair :: AvPair [GeniVal] -> Maybe (AvPair GeniVal)+crushAvPair (AvPair a v) = AvPair a `fmap` crushOne v++crushFlist :: Flist [GeniVal] -> Maybe (Flist GeniVal)+crushFlist = mapM crushAvPair++{-!+deriving instance Binary AvPair+deriving instance NFData AvPair+!-}++-- GENERATED START+++instance (Binary a) => Binary (AvPair a) where+        put (AvPair x1 x2)+          = do put x1+               put x2+        get+          = do x1 <- get+               x2 <- get+               return (AvPair x1 x2)++ +instance (NFData a) => NFData (AvPair a) where+        rnf (AvPair x1 x2) = rnf x1 `seq` rnf x2 `seq` ()+-- GENERATED STOP
+ src/NLP/GenI/Flag.hs view
@@ -0,0 +1,146 @@+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE DeriveDataTypeable #-}+-- GenI surface realiser+-- Copyright (C) 2009 Eric Kow+--+-- This module can be treated as public domain++module NLP.GenI.Flag where++-- This module exists purely for the purpose of making it more convenient+-- to modify the flag set in GenI (by eliminating the need to explicitly+-- export the types for individual flags).  To add a flag:+--+--  1. add a type here+--  2. write the help text in NLP.GenI.Configuration+--  3. add the getopt stuff and find a section for the flag++import Data.List ( find )+import qualified Data.Set as Set+import Data.Maybe ( catMaybes, fromJust )+import Data.Text ( Text )+import Data.Typeable++import NLP.GenI.FeatureStructure ( Flist )+import NLP.GenI.GeniVal ( GeniVal )+import NLP.GenI.Polarity.Types++-- ----------------------------------------------------------------------+-- configuration stuff+-- this stuff really belongs in NLP.GenI.Configuration but we move it here+-- to avoid an import cycle (sigh)+-- ----------------------------------------------------------------------++data Optimisation = PolOpts+                  | AdjOpts+                  | Polarised+                  | NoConstraints+  deriving (Show,Eq,Typeable)++type Instruction = (FilePath, Maybe [Text])++data BuilderType = SimpleBuilder | SimpleOnePhaseBuilder+     deriving (Eq, Typeable)++data GrammarType = GeniHand    -- ^ geni's text format+                 | PreCompiled -- ^ built into geni, no parsing needed+                 | PreAnchored -- ^ lexical selection already done+     deriving (Show, Eq, Typeable)++instance Show BuilderType where+  show SimpleBuilder         = "simple-2p"+  show SimpleOnePhaseBuilder = "simple-1p"++-- ----------------------------------------------------------------------+-- flag core+-- ----------------------------------------------------------------------++{- |+Flags are GenI's internal representation of command line arguments.  We+use phantom existential types (?) for representing GenI flags.  This+makes it simpler to do things such as ``get the value of the MacrosFlg''+whilst preserving type safety (we always know that MacrosFlg is+associated with String).  The alternative would be writing getters and+setters for each flag, and that gets really boring after a while.+-}+data Flag = forall f x . (Eq f, Typeable f, Typeable x) =>+     Flag (x -> f) x deriving (Typeable)++{-+instance Show Flag where+ show (Flag f x) = "Flag " ++ show (f x)+-}++instance Eq Flag where+ (Flag f1 x1) == (Flag f2 x2)+   | (typeOf f1 == typeOf f2) && (typeOf x1 == typeOf x2) =+       (fromJust . cast . f1 $ x1) == (f2 x2)+   | otherwise = False++isFlag :: (Typeable f, Typeable x) => (x -> f) -> Flag -> Bool+isFlag f1 (Flag f2 _) = typeOf f1 == typeOf f2++hasFlag :: (Typeable f, Typeable x) => (x -> f) -> [Flag] -> Bool+hasFlag = any . isFlag++deleteFlag :: (Typeable f, Typeable x) => (x -> f) -> [Flag] -> [Flag]+deleteFlag f = filter (not.(isFlag f))++-- | This only has an effect if the flag is set+modifyFlag :: (Eq f, Typeable f, Typeable x) => (x -> f) -> (x -> x) -> [Flag] -> [Flag]+modifyFlag f m fs =+  case getFlag f fs of+    Nothing -> fs+    Just v  -> setFlag f (m v) fs++setFlag :: (Eq f, Typeable f, Typeable x) => (x -> f) -> x -> [Flag] -> [Flag]+setFlag f v fs = (Flag f v) : tl where tl = deleteFlag f fs++getFlag :: (Typeable f, Typeable x)  => (x -> f) -> [Flag] -> Maybe x+getFlag f fs = do (Flag _ v) <- find (isFlag f) fs ; cast v++getAllFlags :: (Typeable f, Typeable x)  => (x -> f) -> [Flag] -> [x]+getAllFlags f fs = catMaybes [ cast v | flg@(Flag _ v) <- fs, isFlag f flg ]++-- ----------------------------------------------------------------------+-- Below are just the individual flags, which unfortunately have to be+-- defined as separate data types because of our fancy existential+-- data type code.+-- ----------------------------------------------------------------------++newtype BatchDirFlg = BatchDirFlg FilePath deriving (Eq, Typeable)+newtype DisableGuiFlg = DisableGuiFlg () deriving (Eq, Typeable)+newtype DetectPolaritiesFlg = DetectPolaritiesFlg (Set.Set PolarityAttr) deriving (Eq, Typeable)+newtype DumpDerivationFlg = DumpDerivationFlg () deriving (Eq, Typeable)+newtype EarlyDeathFlg = EarlyDeathFlg () deriving (Eq, Typeable)+newtype FromStdinFlg = FromStdinFlg () deriving (Eq, Typeable)+newtype HelpFlg = HelpFlg () deriving (Eq, Typeable)+newtype InstructionsFileFlg = InstructionsFileFlg FilePath deriving (Eq, Typeable)+newtype LexiconFlg = LexiconFlg FilePath deriving (Eq, Typeable)+newtype MacrosFlg = MacrosFlg FilePath deriving (Eq, Typeable)+newtype TracesFlg = TracesFlg FilePath deriving (Eq, Typeable)+newtype MaxStepsFlg = MaxStepsFlg Integer deriving (Eq, Typeable)+newtype MaxResultsFlg = MaxResultsFlg Integer deriving (Eq, Typeable)+newtype MetricsFlg = MetricsFlg [String] deriving (Eq, Typeable)+newtype MorphCmdFlg = MorphCmdFlg String deriving (Eq, Typeable)+newtype MorphInfoFlg = MorphInfoFlg FilePath deriving (Eq, Typeable)+newtype OptimisationsFlg = OptimisationsFlg [Optimisation] deriving (Eq, Typeable)+newtype OutputFileFlg = OutputFileFlg String deriving (Eq, Typeable)+newtype PartialFlg = PartialFlg () deriving (Eq, Typeable)+newtype RankingConstraintsFlg = RankingConstraintsFlg FilePath deriving (Eq, Typeable)+newtype RootFeatureFlg = RootFeatureFlg (Flist GeniVal) deriving (Eq, Typeable)+newtype NoLoadTestSuiteFlg = NoLoadTestSuiteFlg () deriving (Eq, Typeable)+newtype StatsFileFlg = StatsFileFlg FilePath deriving (Eq, Typeable)+newtype TestCaseFlg = TestCaseFlg Text deriving (Eq, Typeable)+newtype TestInstructionsFlg = TestInstructionsFlg [Instruction] deriving (Eq, Typeable)+newtype TestSuiteFlg = TestSuiteFlg FilePath deriving (Eq, Typeable)+newtype TimeoutFlg = TimeoutFlg Int deriving (Eq, Typeable)+newtype VerboseModeFlg = VerboseModeFlg () deriving (Eq, Typeable)+newtype VersionFlg = VersionFlg () deriving (Eq, Typeable)+newtype ViewCmdFlg = ViewCmdFlg String deriving (Eq, Typeable)+newtype BuilderFlg = BuilderFlg BuilderType deriving (Eq, Typeable)+newtype GrammarTypeFlg = GrammarTypeFlg GrammarType deriving (Eq, Typeable)+-- the WeirdFlg exists strictly to please OS X when you launch+-- GenI in an application bundle (double-click)... for some+-- reason it wants to pass an argument to -p+newtype WeirdFlg = WeirdFlg String deriving (Eq, Typeable)
src/NLP/GenI/General.hs view
@@ -20,30 +20,30 @@ --   to replace these functions with versions that are available in the standard --   libraries, or the Haskell platform ones, or on hackage. +{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE DeriveDataTypeable, TypeSynonymInstances #-}+{-# LANGUAGE OverloadedStrings #-} module NLP.GenI.General (         -- * IO         ePutStr, ePutStrLn, eFlush,-        -- ** Strict readFile-        readFile',-        lazySlurp,-        -- ** Timeouts-        withTimeout,-        exitTimeout,         -- * Strings+        isGeniIdentLetter,         dropTillIncluding,         trim,         toUpperHead, toLowerHead,         toAlphaNum,+        quoteString, quoteText,+        clumpBy,         -- * Triples+        first3, second3, third3,         fst3, snd3, thd3,         -- * Lists         map',-        boundsCheck,+        buckets,         isEmptyIntersect,         groupByFM,-        multiGroupByFM,         insertToListMap,-        groupAndCount,+        histogram,         combinations,         mapMaybeM,         repList,@@ -57,32 +57,31 @@         -- * Bit vectors         BitVector,         showBitVector,-       -- * Bugs+        -- * Errors, logging and exceptions         geniBug,+        prettyException,+        mkLogname,         )         where +import Control.Arrow (first)+import Control.Exception (IOException) import Control.Monad (liftM) import Data.Bits (shiftR, (.&.))-import Data.Char (isDigit, isSpace, toUpper, toLower)+import Data.Char (isAlphaNum, isDigit, isSpace, toUpper, toLower) import Data.Function ( on )-import Data.List (foldl', intersect, groupBy, group, sort)+import Data.List (foldl', intersect, inits, intersperse, groupBy, sortBy)+import Data.Typeable ( typeOf, Typeable ) import Data.Tree import System.IO (hPutStrLn, hPutStr, hFlush, stderr)+import System.IO.Error (isUserError, ioeGetErrorString) import qualified Data.Map as Map---- for timeout-import Control.Concurrent-import Control.Exception-import Data.Dynamic(Typeable, typeOf, TyCon, mkTyCon, mkTyConApp, toDyn)-import Data.Unique-import System.Exit(exitWith, ExitCode(ExitFailure))---- for non-lazy IO-import System.IO (openFile, IOMode(ReadMode), hFileSize, hGetBuf)-import System.IO.Unsafe (unsafeInterleaveIO)-import Foreign (mallocForeignPtrBytes, withForeignPtr, ForeignPtr, Ptr, peekElemOff, plusPtr, Word8)-import Data.Char (chr)+import Prelude hiding ( catch )+import Data.Text ( Text )+import qualified Data.Text as T+import qualified Data.Text.Encoding as T+import Data.Binary+import Text.JSON  -- ---------------------------------------------------------------------- -- IO@@ -102,6 +101,13 @@ -- Strings -- ---------------------------------------------------------------------- +instance Binary Text where+  put = put . T.encodeUtf8+  get = liftM T.decodeUtf8 get++isGeniIdentLetter :: Char -> Bool+isGeniIdentLetter x = isAlphaNum x || x `elem` "_'+-."+ trim :: String -> String trim = reverse . (dropWhile isSpace) . reverse . (dropWhile isSpace)  @@ -119,6 +125,44 @@ toLowerHead []    = [] toLowerHead(h:t)  = (toLower h):t +quoteString :: String -> String+quoteString xs = "\"" ++ concatMap helper xs ++ "\""+  where+   helper '"'  = [ '\\', '\"' ]+   helper '\\' = [ '\\', '\\' ]+   helper x    = [ x ]++quoteText :: Text -> Text+quoteText t =+    q `T.append` escape t `T.append` q+  where+    escape = T.replace q escQ . T.replace s escS+    q = "\""+    s = "\\"+    escQ = s `T.append` q+    escS = s `T.append` s++-- | break a list of items into sublists of length < the clump+--   size, taking into consideration that each item in the clump+--   will have a single gap of padding interspersed+--+--   any item whose length is greater than the clump size+--   is put into a clump by itself+--+--   given a length function+--   @clumpBy (length.show) 8 ["hello", "this", "is", "a", "list"]@+clumpBy :: (a -> Int) -> Int -> [a] -> [[a]]+clumpBy f l items = iter [] items+ where+  iter acc [] = reverse acc+  iter acc cs =+   case break toobig (drop 1 $ inits cs) of+        ([],_)    -> next 1           -- first too big+        (_,[])    -> iter (cs:acc) [] -- none too big+        (_,(x:_)) -> next (length x - 1)+   where next n = iter (take n cs : acc) (drop n cs)+  toobig x = (sum . intersperse 1 . map f) x > l+ -- ---------------------------------------------------------------------- -- Alphanumeric sort -- ----------------------------------------------------------------------@@ -149,6 +193,15 @@ -- Triples -- ---------------------------------------------------------------------- +first3 :: (a -> a2) -> (a, b, c) -> (a2, b, c)+first3 f (x,y,z) = (f x, y, z)++second3 :: (b -> b2) -> (a, b, c) -> (a, b2, c)+second3 f (x,y,z) = (x, f y, z)++third3 :: (c -> c2) -> (a, b, c) -> (a, b, c2)+third3 f (x,y,z) = (x, y, f z)+ fst3 :: (a,b,c) -> a fst3 (x,_,_) = x @@ -167,11 +220,6 @@ map' _ [] = [] map' f (x:xs) = let a = f x in a `seq` (a:(map' f xs)) --- | Makes sure that index s is in the bounds of list l.  ---   Surely there must be some more intelligent way to deal with this.-boundsCheck :: Int -> [a] -> Bool-boundsCheck s l = s >= 0 && s < length l- -- | True if the intersection of two lists is empty. isEmptyIntersect :: (Eq a) => [a] -> [a] -> Bool isEmptyIntersect a b = null $ intersect a b@@ -189,15 +237,6 @@       helper acc x = addfn x acc (fn x)   in foldl' helper Map.empty list --- | Same as 'groupByFM', except that we let an item appear in---   multiple groups.  The fn extracts the property from the item,---   and returns multiple results in the form of a list-multiGroupByFM :: (Ord b) => (a -> [b]) -> [a] -> (Map.Map b [a])-multiGroupByFM fn list = -  let addfn  x acc key = insertToListMap key x acc-      helper acc x = foldl' (addfn x) acc (fn x)-  in foldl' helper Map.empty list- {-# INLINE insertToListMap #-} insertToListMap :: (Ord b) => b -> a -> Map.Map b [a] -> Map.Map b [a] insertToListMap k i m =@@ -205,14 +244,15 @@   Nothing -> Map.insert k [i] m   Just p  -> Map.insert k (i:p) m --- | Convert a list of items into a list of tuples (a,b) where---   a is an item in the list and b is the number of times a---   in occurs in the list.-groupAndCount :: (Eq a, Ord a) => [a] -> [(a, Int)]-groupAndCount xs = -  map (\x -> (head x, length x)) grouped-  where grouped = (group.sort) xs+histogram :: Ord a => [a] -> Map.Map a Int+histogram xs = Map.fromListWith (+) $ zip xs (repeat 1) +buckets :: Ord b => (a -> b) -> [a] -> [ (b,[a]) ]+buckets f = map (first head . unzip)+          . groupBy ((==) `on` fst)+          . sortBy (compare `on` fst)+          . map (\x -> (f x, x))+ -- Given a list of lists, return all lists such that one item from each sublist is chosen. -- If returns the empty list if there are any empty sublists. combinations :: [[a]] -> [[a]]@@ -256,9 +296,10 @@  -- | Return pairs of (parent, terminal) preTerminals :: Tree a -> [(a,a)]-preTerminals (Node _ []) = []-preTerminals (Node x ks) =- [ (x,y) | (Node y ys) <- ks, null ys ] ++ concatMap preTerminals ks+preTerminals (Node r xs) = concatMap (helper r) xs+ where+  helper p (Node k []) = [ (p,k) ]+  helper _ (Node p ys) = concatMap (helper p) ys  -- | 'repNode' @fn filt t@ returns a version of @t@ in which the first --   node which @filt@ matches is transformed using @fn@.@@ -307,7 +348,7 @@     _            -> geniBug "Unexpected result in repNode"  -- ------------------------------------------------------------------------- Errors+-- Errors, exceptions and logging -- ----------------------------------------------------------------------  -- | errors specifically in GenI, which is very likely NOT the user's fault.@@ -315,6 +356,15 @@ geniBug s = error $ "Bug in GenI!\n" ++ s ++                     "\nPlease file a report on http://trac.haskell.org/GenI/newticket" +-- stolen from Darcs+prettyException :: IOException -> String+prettyException e | isUserError e = ioeGetErrorString e+prettyException e = show e++-- | The module name for an arbitrary data type+mkLogname :: Typeable a => a -> String+mkLogname = reverse . drop 1 . dropWhile (/= '.') . reverse+          . show . typeOf -- ---------------------------------------------------------------------- -- Intervals -- ----------------------------------------------------------------------@@ -349,75 +399,9 @@ showBitVector min_ x = showBitVector (min_ - 1) (shiftR x 1) ++ (show $ x .&. 1)  -- ------------------------------------------------------------------------- Strict readfile--- Simon Marlow wrote this code on the Haskell mailing list 2005-08-02.--- -------------------------------------------------------------------------- | Using readFile' can be a good idea if you're dealing with not-so-huge--- files (i.e. where you don't want lazy evaluation), because it ensures--- that the handles are closed. No more ``too many open files''-readFile' :: FilePath -> IO String-readFile' f = do-  h <- openFile f ReadMode-  s <- hFileSize h-  fp <- mallocForeignPtrBytes (fromIntegral s)-  len <- withForeignPtr fp $ \buf -> hGetBuf h buf (fromIntegral s)-  lazySlurp fp 0 len--buf_size :: Int-buf_size = 4096 :: Int--lazySlurp :: ForeignPtr Word8 -> Int -> Int -> IO String-lazySlurp fp ix len-  | fp `seq` False = undefined-  | ix >= len = return []-  | otherwise = do-      cs <- unsafeInterleaveIO (lazySlurp fp (ix + buf_size) len)-      ws <- withForeignPtr fp $ \p -> loop (min (len-ix) buf_size - 1)-					((p :: Ptr Word8) `plusPtr` ix) cs-      return ws- where-  loop :: Int -> Ptr Word8 -> String -> IO String-  loop sublen p acc-    | sublen `seq` p `seq` False = undefined-    | sublen < 0 = return acc-    | otherwise = do-       w <- peekElemOff p sublen-       loop (sublen-1) p (chr (fromIntegral w):acc)---- ------------------------------------------------------------------------- Timeouts+-- JSON -- ---------------------------------------------------------------------- -data TimeOut = TimeOut Unique--timeOutTc :: TyCon-timeOutTc = mkTyCon "TimeOut"--instance Typeable TimeOut where-    typeOf _ = mkTyConApp timeOutTc []--withTimeout :: Integer-            -> IO a -- ^ action to run upon timing out-            -> IO a -- ^ main action to run-            -> IO a-withTimeout secs on_timeout action =- do parent  <- myThreadId-    i       <- newUnique-    block $ do-      timeout <- forkIO (timeout_thread secs parent i)-      Control.Exception.catchDyn-        ( unblock $ do result <- action-                       killThread timeout-                       return result )-        ( \ex -> case ex of-                 TimeOut u | u == i -> unblock on_timeout-                 _ -> killThread timeout >>= throwDyn ex )- where-  timeout_thread secs_ parent i =-   do threadDelay $ (fromInteger secs_) * 1000000-      throwTo parent (DynException $ toDyn $ TimeOut i)---- | Like 'exitFailure', except that we return with a code that we reserve for timing out-exitTimeout :: IO ()-exitTimeout = exitWith $ ExitFailure 2+instance JSON Text where+    readJSON = fmap T.pack . readJSON+    showJSON = showJSON . T.unpack
− src/NLP/GenI/Geni.lhs
@@ -1,1149 +0,0 @@-% GenI surface realiser-% Copyright (C) 2005 Carlos Areces and Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.--\chapter{Geni}-\label{cha:Geni}--Geni is the interface between the front and backends of the generator. The GUI-and the console interface both talk to this module, and in turn, this module-talks to the input file parsers and the surface realisation engine.  This-module also does lexical selection and anchoring because these processes might-involve some messy IO performance tricks.--\begin{code}-module NLP.GenI.Geni (-             -- * main interface-             ProgState(..), ProgStateRef, emptyProgState,-             initGeni,-             runGeni, runGeniWithSelector,-             GeniResult(..), ResultType(..),-             -- * helpers-             lemmaSentenceString, prettyResult,-             showRealisations, groupAndCount,-             getTraces, Selector,-             loadEverything, loadLexicon, loadGeniMacros,-             loadTestSuite, loadTargetSemStr,-             loadRanking, readRanking,-             combine,--             -- used by auxiliary tools only-             chooseLexCand,-             )-where-\end{code}--\ignore{-\begin{code}-import Control.Applicative ((<$>),(<*>))-import Control.Arrow ((&&&))-import Control.Monad.Error-import Control.Monad (unless)--import Data.Binary (Binary, decodeFile)-import Data.Function ( on )-import Data.IORef (IORef, readIORef, modifyIORef)-import Data.List-import Data.List.Split ( wordsBy )-import qualified Data.Map as Map-import Data.Maybe (mapMaybe, fromMaybe, isJust)-import Data.Tree (Tree(Node))-import Data.Typeable (Typeable)--import qualified System.IO.UTF8 as UTF8--import System.IO.Unsafe (unsafePerformIO)-import Text.JSON--- import System.Process ---import NLP.GenI.General(filterTree, repAllNode,-    groupAndCount, multiGroupByFM,-    geniBug,-    repNodeByNode,-    fst3,-    ePutStr, ePutStrLn, eFlush,-    )--import NLP.GenI.Btypes-  (Macros, MTtree, ILexEntry, Lexicon,-   replace, replaceList,-   Sem, SemInput, TestCase(..), sortSem, subsumeSem, params,-   GeniVal(GConst), fromGVar, AvPair(..),-   GNode(ganchor, gnname, gup, gdown, gaconstr, gtype, gorigin),-   GType(Subs, Other),-   isemantics, ifamname, iword, iparams, iequations,-   iinterface, ifilters,-   isempols,-   toKeys,-   showLexeme, showSem,-   pidname, pfamily, pinterface, ptype, psemantics, ptrace,-   setAnchor, setLexeme, tree, unifyFeat,-   alphaConvert,-   )-import NLP.GenI.BtypesBinary ()--import NLP.GenI.Tags (Tags, TagElem, emptyTE,-             idname, ttreename,-             ttype, tsemantics, ttree, tsempols,-             tinterface, ttrace,-             setTidnums) --import NLP.GenI.Configuration-  ( Params, getFlagP, hasFlagP, hasOpt, Optimisation(NoConstraints)-  , MacrosFlg(..), LexiconFlg(..), TestSuiteFlg(..), TestCaseFlg(..)-  , MorphInfoFlg(..), MorphCmdFlg(..)-  , RankingConstraintsFlg(..)-  , PartialFlg(..)-  , FromStdinFlg(..), VerboseModeFlg(..)-  , NoLoadTestSuiteFlg(..)-  , TracesFlg(..)-  , grammarType-  , GrammarType(..) )--import qualified NLP.GenI.Builder as B--import NLP.GenI.GeniParsers (geniMacros, geniTagElems,-                    geniLexicon, geniTestSuite,-                    geniTestSuiteString, geniSemanticInput,-                    geniMorphInfo,-                    parseFromFile, runParser, Parser,-                    )-import NLP.GenI.Morphology-import NLP.GenI.OptimalityTheory-import NLP.GenI.Statistics (Statistics)---- import CkyBuilder --- import SimpleBuilder (simpleBuilder)-\end{code}-}--\begin{code}-myEMPTY :: String-myEMPTY = "MYEMPTY" -\end{code}--% ---------------------------------------------------------------------\section{ProgState}-% ----------------------------------------------------------------------\begin{code}-data ProgState = ST{ -- | the current configuration being processed-                    pa     :: Params,-                    ---                    gr       :: Macros,-                    le       :: Lexicon,-                    morphinf :: MorphFn,-                    ts       :: SemInput, -                    -- | names of test case to run-                    tcase    :: String, -                    -- | name, original string (for gui), sem-                    tsuite   :: [TestCase],-                    -- | OT constraints (optional)-                    ranking  :: OtRanking,-                    -- | simplified traces (optional)-                    traces   :: [String],-                    -- | any warnings accumulated during realisation-                    --   (most recent first)-                    warnings :: [String]-               }--type ProgStateRef = IORef ProgState---- | The program state when you start GenI for the very first time-emptyProgState :: Params -> ProgState-emptyProgState args =- ST { pa = args-    , gr = []-    , le = Map.empty-    , morphinf = const Nothing-    , ts = ([],[],[])-    , tcase = []-    , tsuite = []-    , traces = []-    , ranking = []-    , warnings = []-    }---- | Log another warning in our internal program state-addWarning :: ProgStateRef -> String -> IO ()-addWarning pstRef s = modifyIORef pstRef $ \p -> p { warnings = s : warnings p }-\end{code}--% ---------------------------------------------------------------------\section{Interface}-\subsection{Loading and parsing}-% ----------------------------------------------------------------------We have one master function that loads all the files GenI is expected to-use.  This just calls the sub-loaders below, some of which are exported-for use by the graphical interface.  The master function also makes sure-to complain intelligently if some of the required files are missing.--\begin{code}-loadEverything :: ProgStateRef -> IO() -loadEverything pstRef =-  do pst <- readIORef pstRef-     ---     let config   = pa pst-         isMissing f = not $ hasFlagP f config-     -- grammar type-         isNotPreanchored = grammarType config /= PreAnchored-         isNotPrecompiled = grammarType config /= PreCompiled-         useTestSuite =  isMissing FromStdinFlg-                      && isMissing NoLoadTestSuiteFlg-     -- display -     let errormsg =-           concat $ intersperse ", " [ msg | (con, msg) <- errorlst, con ]-         errorlst =-              [ (isNotPrecompiled && isMissing MacrosFlg,-                "a tree file")-              , (isNotPreanchored && isMissing LexiconFlg,-                "a lexicon file")-              , (useTestSuite && isMissing TestSuiteFlg,-                "a test suite") ]-     unless (null errormsg) $ fail ("Please specify: " ++ errormsg)-     -- we only have to read in grammars from the simple format-     case grammarType config of -        PreAnchored -> return ()-        PreCompiled -> return ()-        _        -> loadGeniMacros pstRef-     -- we don't have to read in the lexicon if it's already pre-anchored-     when isNotPreanchored $ loadLexicon pstRef-     -- in any case, we have to...-     loadMorphInfo pstRef-     when useTestSuite $ loadTestSuite pstRef >> return ()-     -- the trace filter file-     loadTraces pstRef-     -- OT ranking-     loadRanking pstRef-\end{code}--The file loading functions all work the same way: we load the file,-and try to parse it.  If this doesn't work, we just fail in IO, and-GenI dies.  If we succeed, we update the program state passed in as-an IORef.--\begin{code}-loadLexicon :: ProgStateRef -> IO ()-loadLexicon pstRef =-    do let getSem l  = isemantics l-           sorter l  = l { isemantics = (sortSem . getSem) l }-           cleanup   = mapBySemKeys isemantics . map sorter-       xs <- loadThingOrDie LexiconFlg "lexicon" pstRef-         (parseFromFileOrFail geniLexicon)-       modifyIORef pstRef (\p -> p { le = cleanup xs })---- | The macros are stored as a hashing function in the monad.-loadGeniMacros :: ProgStateRef -> IO ()-loadGeniMacros pstRef =-  do xs <- loadThingOrDie MacrosFlg "trees" pstRef parser-     modifyIORef pstRef (\p -> p { gr = xs })-  where parser = parseFromFileMaybeBinary geniMacros---- | The results are stored as a lookup function in the monad.-loadMorphInfo :: ProgStateRef -> IO ()-loadMorphInfo pstRef =- do xs <- loadThingOrIgnore MorphInfoFlg "morphological info" pstRef parser-    modifyIORef pstRef (\p -> p { morphinf = readMorph xs } )- where parser = parseFromFileOrFail geniMorphInfo--loadTraces :: ProgStateRef -> IO ()-loadTraces pstRef =- do xs <- loadThingOrIgnore TracesFlg "traces" pstRef-             (\f -> lines `fmap` readFile f)-    modifyIORef pstRef (\p -> p {traces = xs})--loadRanking :: ProgStateRef -> IO ()-loadRanking pstRef =- do config <- pa `fmap` readIORef pstRef-    let verbose = hasFlagP VerboseModeFlg config-    case getFlagP RankingConstraintsFlg config of-      Nothing -> return ()-      Just f  -> do r <- readRanking verbose f-                    modifyIORef pstRef (\p -> p { ranking = r })--readRanking :: Bool -- ^ verbose-            -> FilePath -> IO OtRanking-readRanking verbose f =- do when verbose $ do-       ePutStr $ unwords [ "Loading OT constraints", f ++ "... " ]-       eFlush-    mr <- (resultToEither . decode) `fmap` UTF8.readFile f -- utf-8?-    when verbose $ ePutStr "done"-    either fail return mr-\end{code}--\subsubsection{Target semantics}--Reading in the target semantics (or test suite) is a little more-complicated.  It follows the same general schema as above, except-that we parse the file twice: once for our internal representation,-and once to get a string representation of each test case.  The-string representation is for the graphical interface; it avoids us-figuring out how to pretty-print things because we can assume the-user will format it the way s/he wants.--\begin{code}--- | Stores the results in the tcase and tsuite fields-loadTestSuite :: ProgStateRef -> IO [TestCase]-loadTestSuite pstRef = do-  config <- pa `fmap` readIORef pstRef-  let parser f = do-         sem   <- parseFromFileOrFail geniTestSuite f-         mStrs <- parseFromFileOrFail geniTestSuiteString f-         return $ zip sem mStrs-      updater s x =-        x { tsuite = s-          , tcase  = fromMaybe "" $ getFlagP TestCaseFlg config}-      cleanup (tc,str) =-        tc { tcSem = (sortSem sm, sort sr, lc)-           , tcSemString = str }-        where (sm, sr, lc) = tcSem tc-  xs <- map cleanup `fmap` loadThingOrDie TestSuiteFlg "test suite" pstRef parser-  modifyIORef pstRef (updater xs)-  return xs-\end{code}--Sometimes, the target semantics does not come from a file, but from-the graphical interface, so we also provide the ability to parse an-arbitrary string as the semantics.--\begin{code}--- | Updates program state the same way as 'loadTestSuite'-loadTargetSemStr :: ProgStateRef -> String -> IO ()-loadTargetSemStr pstRef str = -    do parseSem-    where-       parseSem = do-         let sem = runParser geniSemanticInput () "" str-         case sem of-           Left  err -> fail (show err)-           Right sr  -> modifyIORef pstRef (\x -> x{ts = smooth sr})-       smooth (s,r,l) = (sortSem s, sort r, l)-\end{code}--\subsubsection{Helpers for loading files}--\begin{code}-loadThingOrIgnore, loadThingOrDie :: forall f a . (Eq f, Show f, Typeable f)-           => (FilePath -> f) -- ^ flag-           -> String-           -> ProgStateRef-           -> (FilePath -> IO [a])-           -> IO [a]---- | Load the file if the relevant option is set, otherwise ignore-loadThingOrIgnore flag description pstRef parser =- do config <- pa `fmap` readIORef pstRef-    case getFlagP flag config of-      Nothing -> return []-      Just f  -> loadThing f description pstRef parser---- | Load the file if the relevant option is set, otherwise complain and die-loadThingOrDie flag description pstRef parser =- do config <- pa `fmap` readIORef pstRef-    case getFlagP flag config of-      Nothing -> fail $ "Please specify a " ++ description ++ "!"-      Just f  -> loadThing f description pstRef parser--loadThing :: FilePath             -- ^ file to load-          -> String               -- ^ description-          -> ProgStateRef-          -> (FilePath -> IO [a]) -- ^ parsing cmd-          -> IO [a]-loadThing filename description pstRef parser =- do config <- pa `fmap` readIORef pstRef-    let verbose = hasFlagP VerboseModeFlg config-    when verbose $ do-       ePutStr $ unwords [ "Loading",  description, filename ++ "... " ]-       eFlush-    theTs <- parser filename-    when verbose $ ePutStr $ (show $ length theTs) ++ " entries\n"-    return theTs--parseFromFileOrFail :: Parser a -> FilePath -> IO a-parseFromFileOrFail p f = parseFromFile p f >>= either (fail.show) (return)--parseFromFileMaybeBinary :: Binary a-                         => Parser a-                         -> FilePath-                         -> IO a-parseFromFileMaybeBinary p f =- if (".genib" `isSuffixOf` f)-    then decodeFile f-    else parseFromFileOrFail p f-\end{code}--% ---------------------------------------------------------------------\subsection{Surface realisation - entry point}-% ----------------------------------------------------------------------This is your basic entry point.  You call this if the only thing you want to do-is run the surface realiser.--\begin{enumerate}-\item It initialises the realiser (lexical selection, among other things),-      via \fnref{initGeni}-\item It runs the builder (the surface realisation engine proper)-\item It unpacks the builder results -\item It finalises the results (morphological generation)-\end{enumerate}--\begin{code}-data GeniResult = GeniResult- { grLemmaSentence     :: B.LemmaPlusSentence- , grRealisations :: [String]- , grDerivation   :: B.Derivation- , grLexSelection :: [ GeniLexSel ]- , grRanking      :: Int- , grViolations   :: [ OtViolation ]- , grResultType   :: ResultType- } deriving (Ord, Eq)--data GeniLexSel = GeniLexSel- { nlTree  :: String- , nlTrace :: [String]- } deriving (Ord, Eq)--data ResultType = CompleteResult | PartialResult deriving (Ord, Eq)---- | Returns a list of sentences, a set of Statistics, and the generator state.---   The generator state is mostly useful for debugging via the graphical interface.---   Note that we assumes that you have already loaded in your grammar and---   parsed your input semantics.-runGeni :: ProgStateRef -> B.Builder st it Params -> IO ([GeniResult], Statistics, st)-runGeni pstRef builder = runGeniWithSelector pstRef defaultSelector builder--runGeniWithSelector :: ProgStateRef -> Selector -> B.Builder st it Params -> IO ([GeniResult], Statistics, st)-runGeniWithSelector pstRef  selector builder =-  do pst <- readIORef pstRef-     let config = pa pst-         run    = B.run builder-         unpack = B.unpack builder-     -- step 1: lexical selection-     initStuff <- initGeniWithSelector pstRef selector-     -- step 2: chart generation-     let (finalSt, stats) = run initStuff config-     -- step 3: unpacking-     let uninflected = unpack finalSt-         tryPartial  = null uninflected && hasFlagP PartialFlg config-         rawResults  = if tryPartial then B.partial builder finalSt else uninflected-         resultTy    = if tryPartial then PartialResult else CompleteResult-     -- step 4: post-processing-     results <- finaliseResults pstRef resultTy rawResults-     return (results, stats, finalSt)-\end{code}--% ---------------------------------------------------------------------\subsection{Surface realisation - sub steps}-% ----------------------------------------------------------------------Below are the initial and final steps of \fnreflite{runGeni}.  These functions-are seperated out so that they may be individually called from the graphical-debugger.  The middle steps (running and unpacking the builder) depend on your-builder implementation.--\begin{code}--- | 'initGeni' performs lexical selection and strips the input semantics of---   any morpohological literals-initGeni :: ProgStateRef -> IO (B.Input)-initGeni pstRef = initGeniWithSelector pstRef defaultSelector--initGeniWithSelector :: ProgStateRef -> Selector -> IO (B.Input)-initGeniWithSelector pstRef lexSelector =- do -- disable constraints if the NoConstraintsFlg anti-optimisation is active-    modifyIORef pstRef-      (\p -> if hasOpt NoConstraints (pa p)-             then p { ts = (fst3 (ts p),[],[]) }-             else p)-    -- lexical selection-    (cand, lexonly) <- lexSelector pstRef-    pst <- readIORef pstRef-    -- strip morphological predicates-    let (tsem,tres,lc) = ts pst-        tsem2 = stripMorphSem (morphinf pst) tsem-            ---    let initStuff = B.Input -          { B.inSemInput = (tsem2, tres, lc)-          , B.inLex   = lexonly -          , B.inCands = map (\c -> (c,-1)) cand-          }-    return initStuff ---- | 'finaliseResults' does any post-processing steps that we want to integrate---   into mainline GenI.  So far, this consists of morphological realisation and---   OT ranking-finaliseResults :: ProgStateRef -> ResultType -> [B.Output] -> IO [GeniResult]-finaliseResults pstRef ty os =- do pst <- readIORef pstRef-    -- morph TODO: make this a bit safer-    mss <- case getFlagP MorphCmdFlg (pa pst) of-             Nothing  -> return $ map sansMorph sentences-             Just cmd -> map snd `fmap` inflectSentencesUsingCmd cmd sentences-    -- OT ranking-    let unranked = zipWith (sansRanking pst) os mss-        rank = rankResults (getTraces pst) grDerivation (ranking pst)-    return . map addRanking . rank $ unranked- where-  sentences = map fst os-  sansRanking pst (l,d) rs =-    GeniResult { grLemmaSentence = l-               , grRealisations = rs-               , grDerivation   = d-               , grLexSelection = map (\x -> GeniLexSel x (getTraces pst x)) (B.lexicalSelection d)-               , grRanking = -1-               , grViolations = []-               , grResultType = ty-               }-  addRanking (i,res,vs) = res { grViolations = vs, grRanking = i }-\end{code}--% ---------------------------------------------------------------------\subsection{Displaying results}-% ----------------------------------------------------------------------\begin{code}--- | Show the sentences produced by the generator, in a relatively compact form-showRealisations :: [String] -> String-showRealisations sentences =-  let sentencesGrouped = map (\ (s,c) -> s ++ countStr c) g-                         where g = groupAndCount sentences -      countStr c = if c > 1 then " (" ++ show c ++ " instances)"-                            else ""-  in if null sentences-     then "(none)"-     else unlines sentencesGrouped---- | No morphology! Pretend the lemma string is a sentence-lemmaSentenceString :: GeniResult -> String-lemmaSentenceString = unwords . map lpLemma . grLemmaSentence--prettyResult :: ProgState -> GeniResult -> String-prettyResult pst nr =-  concat . intersperse "\n" . map showOne . grRealisations $ nr- where-  showOne str = show theRanking  ++ ". " ++ str ++ "\n" ++ violations-  violations  = prettyViolations tracesFn verbose (grViolations nr)-  theRanking  = grRanking nr-  verbose  = hasFlagP VerboseModeFlg (pa pst)-  tracesFn = getTraces pst---- | 'getTraces' is most likely useful for grammars produced by a---   metagrammar system.  Given a tree name, we retrieve the ``trace''---   information from the grammar for all trees that have this name.  We---   assume the tree name was constructed by GenI; see the source code for---   details.-getTraces :: ProgState -> String -> [String]-getTraces pst tname =-  filt $ concat [ ptrace t | t <- gr pst, pidname t == readPidname tname ]-  where-   filt = case traces pst of-          []    -> id-          theTs -> filter (`elem` theTs)---- | We assume the name was constructed by 'combineName'-readPidname :: String -> String-readPidname n =-  case wordsBy (== ':') n of-  (_:_:p:_) -> p-  _         -> geniBug "readPidname or combineName are broken"-\end{code}--% ---------------------------------------------------------------------\section{Lexical selection}-\label{sec:candidate_selection} \label{sec:lexical_selecetion} \label{par:lexSelection}-% ----------------------------------------------------------------------\paragraph{runLexSelection} \label{fn:runLexSelection} determines which-candidates trees which will be used to generate the current target semantics.  -In addition to the anchored candidate trees, we also return the lexical items -themselves.  This list of lexical items is useful for debugging a grammar; -it lets us know if GenI managed to lexically select something, but did not -succeed in anchoring it.--\begin{code}-runLexSelection :: ProgStateRef -> IO ([TagElem], [ILexEntry])-runLexSelection pstRef =- do pst <- readIORef pstRef-    -- select lexical items first-    let (tsem,_,litConstrs) = ts pst-        lexicon  = le pst-        lexCand   = chooseLexCand lexicon tsem-        config   = pa pst-        verbose  = hasFlagP VerboseModeFlg config-    -- then anchor these lexical items to trees-    let grammar = gr pst-        combineWithGr l =-         do let (lexCombineErrors, res) = combineList grammar l-                familyMembers = [ p | p <- grammar, pfamily p == ifamname l ]-            mapM_ (addWarning pstRef . showErr) $ compressLexCombineErrors-                                                $ lexCombineErrors-            -- snippets of error message-            let lexeme = showLexeme.iword $ l-                _outOfFamily n = show n ++ "/" ++ (show $ length familyMembers)-                                 ++ " instances of " ++ lexeme ++ ":" ++ ifamname l-            -- print out missing coanchors list-            case concatMap (missingCoanchors l) familyMembers of-              [] -> return ()-              cs -> mapM_ showWarning . group . sort $ cs-                    where showWarning [] = geniBug "silly error in Geni.runLexSelection"-                          showWarning xs@(x0:_) = addWarning pstRef $ "Missing co-anchor '" ++ x0 ++ "'" ++ " in " ++ _outOfFamily (length xs) ++ "."-            -- print out enrichment errors-{--            unless (null enrichEs) $ do-                let numDiscards = length enrichEs-                    badEnrichments = [ av | av <- iequations l, hasMatch av ]-                    hasMatch (a,_) = any (== parsePathEq a) errLocs-                    errLocs = map eeLocation enrichEs-                ePutStrLn $      "Warning: Discarded "-                            ++ _outOfFamily numDiscards-                            ++ "\n         due to enrichment failure with "-                            ++ "[" ++ showPairs badEnrichments ++ "]."-            mapM (ePutStrLn.show) otherEs--}--            -- FIXMENOW when (not.null $ errs) $ ePutStrLn (unlines errs)-            return res-    cand <- case grammarType config of-              PreAnchored  -> readPreAnchored pst-              _            -> concat `liftM` mapM combineWithGr lexCand-    -- attach any morphological information to the candidates-    let considerMorph = attachMorph (morphinf pst) tsem-    -- filter out candidates which do not fulfill the trace constraints-    let matchesLc t = all (`elem` myTrace) constrs-          where constrs = concat [ cs | (l,cs) <- litConstrs, l `elem` mySem ]-                mySem   = tsemantics t-                myTrace = ttrace t-        considerLc = filter matchesLc-    -- filter out candidates whose semantics has bonus stuff which does-    -- not occur in the input semantics-    let considerCoherency = filter (all (`elem` tsem) . tsemantics)-        considerHasSem    = filter (not . null . tsemantics)-    ---    let candFinal = setTidnums . considerCoherency . considerHasSem-                  . considerLc . considerMorph $ cand-        indent  x = ' ' : x-        unlinesIndentAnd :: (x -> String) -> [x] -> String-        unlinesIndentAnd f = unlines . map (indent . f)-    when verbose $-      do ePutStrLn $ "Lexical items selected:\n" ++ (unlinesIndentAnd (showLexeme.iword) lexCand)-         ePutStrLn $ "Trees anchored (family) :\n" ++ (unlinesIndentAnd idname candFinal)-    -- lexical selection failures-    let missedSem  = tsem \\ (nub $ concatMap tsemantics candFinal)-        hasTree l = isJust $ find (\t -> tsemantics t == lsem) cand-          where lsem = isemantics l-        missedLex = filter (not.hasTree) lexCand-    unless (null missedSem) $ addWarning pstRef $ "no lexical selection for " ++ showSem missedSem-    unless (null missedLex) $ forM_ missedLex $ \l -> addWarning pstRef $-        "'" ++ showLex l ++ "' was lexically selected, but not anchored to any trees"-    return (candFinal, lexCand)- where showLex l = (showLexeme $ iword l) ++ "-" ++ (ifamname l)-       showErr (c, e) = show e ++ " (" ++ show c ++ " times)"--compressLexCombineErrors :: [LexCombineError] -> [(Int, LexCombineError)]-compressLexCombineErrors = map (length &&& head) . groupBy h- where-  h (EnrichError m1 l1 _) (EnrichError m2 l2 _) = pfamily m1 == pfamily m2 &&-                                                  iword l1 == iword l2-  h _ _ = False---- | Select and returns the set of entries from the lexicon whose semantics---   subsumes the input semantics.-chooseLexCand :: Lexicon -> Sem -> [ILexEntry]-chooseLexCand slex tsem = -  let keys = toKeys tsem-      -- we choose candidates that match keys-      lookuplex t = Map.findWithDefault [] t slex-      cand  = concatMap lookuplex $ myEMPTY : keys-      -- and refine the selection... -      cand2 = chooseCandI tsem cand-      -- treat synonyms as a single lexical entry-      -- FIXME: disabled see mergeSynonyms for explanation-      -- cand3 = mergeSynonyms cand2-  in cand2-\end{code}--With a helper function, we refine the candidate selection by-instatiating the semantics, at the same time filtering those which-do not stay within the target semantics, and finally eliminating -the duplicates.--\begin{code}-chooseCandI :: Sem -> [ILexEntry] -> [ILexEntry]-chooseCandI tsem cand =-  let replaceLex i (sem,sub) = -        (replace sub i) { isemantics = sem }-      ---      helper :: ILexEntry -> [ILexEntry]-      helper l = if null sem then [l]-                 else map (replaceLex l) psubsem-        where psubsem = subsumeSem tsem sem-              sem = isemantics l-      ---  in nub $ concatMap helper cand -\end{code}--A semantic key is a semantic literal boiled down to predicate plus arity-(see section \ref{btypes_semantics}).---\begin{code}--- | 'mapBySemKeys' @xs fn@ organises items (@xs@) by their semantic key---   (retrieved by @fn@).  An item may have multiple keys.----  This is used to organise the lexicon by its semantics.-mapBySemKeys :: (a -> Sem) -> [a] -> Map.Map String [a]-mapBySemKeys semfn xs = -  let gfn t = if (null s) then [myEMPTY] else toKeys s -              where s = semfn t-  in multiGroupByFM gfn xs-\end{code}--\fnlabel{mergeSynonyms} is a factorisation technique that uses-atomic disjunction to merge all synonyms into a single lexical-entry.  Two lexical entries are considered synonyms if their-semantics match and they point to the same tree families.--FIXME: 2006-10-11 - note that this is no longer being used,-because it breaks the case where two lexical entries differ-only by their use of path equations.  Perhaps it's worthwhile-just to add a check that the path equations match exactly.--\begin{code}-{--mergeSynonyms :: [ILexEntry] -> [ILexEntry]-mergeSynonyms lexEntry =-  let mergeFn l1 l2 = l1 { iword = (iword l1) ++ (iword l2) }-      keyFn l = (ifamname l, isemantics l)   -      synMap = foldr helper Map.empty lexEntry-        where helper x acc = Map.insertWith mergeFn (keyFn x) x acc -  in Map.elems synMap--}-\end{code}--% ---------------------------------------------------------------------\subsection{Basic anchoring}-\label{sec:combine_macros}-% ----------------------------------------------------------------------This section of the code helps you to combined a selected lexical item with-a macro or a list of macros.  This is a process that can go fail for any-number of reasons, so we try to record the possible failures for book-keeping.--\begin{code}-data LexCombineError =-        BoringError String-      | EnrichError { eeMacro    :: MTtree-                    , eeLexEntry :: ILexEntry-                    , eeLocation :: PathEqLhs }-     | OtherError MTtree ILexEntry String--instance Error LexCombineError where-  noMsg    = strMsg "error combining items"-  strMsg s = BoringError s--instance Show LexCombineError where- show (BoringError s)    = s- show (OtherError t l s) = s ++ " on " ++ pfamily t ++ " (" ++ (showLexeme $ iword l) ++ ")"- show (EnrichError t l _) = show (OtherError t l "enrichment error")-\end{code}--The first step in lexical selection is to collect all the features and-parameters that we want to combine.--\begin{code}--- | 'combine' @macros lex@ creates the 'Tags' repository combining lexical---   entries and un-anchored trees from the grammar. It also unifies the---   parameters used to specialize un-anchored trees and propagates additional---   features given in the 'ILexEntry'.-combine :: Macros -> Lexicon -> Tags-combine gram lexicon =-  let helper li = mapEither (combineOne li) macs-       where tn   = ifamname li-             macs = [ t | t <- gram, pfamily t == tn ]-  in Map.map (\e -> concatMap helper e) lexicon --mapEither :: (a -> Either l r) -> [a] -> [r]-mapEither fn = mapMaybe (\x -> either (const Nothing) Just $ fn x)-\end{code}--\begin{code}--- | Given a lexical item, looks up the tree families for that item, and---   anchor the item to the trees.-combineList :: Macros -> ILexEntry-            -> ([LexCombineError],[TagElem]) -- ^ any warnings, plus the results-combineList gram lexitem =-  case [ t | t <- gram, pfamily t == tn ] of-       []   -> ([BoringError $ "Family " ++ tn ++ " not found in Macros"],[])-       macs -> unzipEither $ map (combineOne lexitem) macs-  where tn = ifamname lexitem--unzipEither :: (Error e, Show b) => [Either e b] -> ([e], [b])-unzipEither es = helper ([],[]) es where- helper accs [] = accs- helper (eAcc, rAcc) (Left e : next)  = helper (e:eAcc,rAcc) next- helper (eAcc, rAcc) (Right r : next) = helper (eAcc,r:rAcc) next-\end{code}--\begin{code}--- | Combine a single tree with its lexical item to form a bonafide TagElem.---   This process can fail, however, because of filtering or enrichement-combineOne :: ILexEntry -> MTtree -> Either LexCombineError TagElem-combineOne lexRaw eRaw = -- Maybe monad- -- trace ("\n" ++ (show wt)) $- do let l1 = alphaConvert "-l" lexRaw-        e1 = alphaConvert "-t" eRaw-    (l,e) <- unifyParamsWithWarning (l1,e1)-             >>= unifyInterfaceUsing iinterface-             >>= unifyInterfaceUsing ifilters -- filtering-             >>= enrichWithWarning -- enrichment-    let name = concat $ intersperse ":" $ filter (not.null)-                 [ head (iword l) , pfamily e , pidname e ]-    return $ emptyTE-              { idname = name-              , ttreename = pfamily e-              , ttype = ptype e-              , ttree = setOrigin name . setLemAnchors . setAnchor (iword l) $ tree e-              , tsemantics  =-                 sortSem $ case psemantics e of-                           Nothing -> isemantics l-                           Just s  -> s-              , tsempols    = isempols l-              , tinterface  = pinterface e-              , ttrace      = ptrace e-              }- where-  unifyParamsWithWarning (l,t) =-   -- trace ("unify params " ++ wt) $-   let lp = iparams l-       tp = map fromGVar $ params t-       psubst = zip tp lp-   in if (length lp) /= (length tp)-      then Left $ OtherError t l $ "Parameter length mismatch"-      else Right $ (replaceList psubst l, replaceList psubst t)-  ---  unifyInterfaceUsing ifn (l,e) =-    -- trace ("unify interface" ++ wt) $-    case unifyFeat (ifn l) (pinterface e) of-    Nothing             -> Left $ OtherError e l $ "Interface unification error"-    Just (int2, fsubst) -> Right $ (replace fsubst l, e2)-                           where e2 = (replace fsubst e) { pinterface = int2 }-  ---  enrichWithWarning (l,e) =-    -- trace ("enrich" ++ wt) $-    do e2 <- enrich l e-       return (l,e2)-\end{code}--\subsubsection{Enrichment}--Enrichment is a process which adds features to either the interface, an-explicitly named node or the co-anchor of a lexically selected tree.  The-enrichement information comes from the lexicon in the form of a path equations-which specify-\begin{enumerate}-\item the location-\item top or bottom-\item the attribute-\item what value to associate with it-\end{enumerate}--The conventions taken by GenI for path equations are:--\begin{tabular}{|l|p{8cm}|}-\hline-\verb!interface.foo=bar! &-\fs{foo=bar} is unified into the interface (not the tree) \\-\hline-\verb!anchor.bot.foo=bar! &-\fs{foo=bar} is unified into the bottom feature of the node-which is marked anchor.  \\-\hline-\verb!toto.top.foo=bar! &-\fs{foo=bar} is unified into the top feature of node named toto \\-\hline-\verb!toto.bot.foo=bar! &-\fs{foo=bar} is unified into the bot feature of node named toto \\-\hline-\verb!anchor.foo=bar! &-same as \verb!anchor.bot.foo=bar!  \\-\hline-\verb!anc.whatever...! &-same as \verb!anchor.whatever...!  \\-\hline-\verb!top.foo=bar! &-same as \verb!anchor.top.foo=bar!  \\-\hline-\verb!bot.foo=bar! &-same as \verb!anchor.bot.foo=bar!  \\-\hline-\verb!foo=bar! &-same as \verb!anchor.bot.foo=bar!  \\-\hline-\verb!toto.foo=bar! &-same as \verb!toto.top.foo=bar! (creates a warning) \\-\hline-\end{tabular}--\begin{code}--- | (node, top, att) (node is Nothing if anchor)-type PathEqLhs  = (String, Bool, String)-type PathEqPair = (PathEqLhs, GeniVal)--enrich :: ILexEntry -> MTtree -> Either LexCombineError MTtree-enrich l t =- do -- separate into interface/anchor/named-    let (intE, namedE) = lexEquations l-    -- enrich the interface and everything else-    t2 <- foldM enrichInterface t intE-    -- enrich everything else-    foldM (enrichBy l) t2 namedE- where-  toAvPair ((_,_,a),v) = AvPair a v-  enrichInterface tx en =-    do (i2, isubs) <- unifyFeat [toAvPair en] (pinterface tx)-         `catchError` (\_ -> throwError $ ifaceEnrichErr en)-       return $ (replace isubs tx) { pinterface = i2 }-  ifaceEnrichErr (loc,_) = EnrichError-    { eeMacro    = t-    , eeLexEntry = l-    , eeLocation = loc }--enrichBy :: ILexEntry -- ^ lexeme (for debugging info)-         -> MTtree-         -> (PathEqLhs, GeniVal) -- ^ enrichment eq-         -> Either LexCombineError MTtree-enrichBy lexEntry t (eqLhs, eqVal) =- case seekCoanchor eqName t of- Nothing -> return t -- to be robust, we accept if the node isn't there- Just a  ->-        do let tfeat = (if eqTop then gup else gdown) a-           (newfeat, sub) <- unifyFeat [AvPair eqAtt eqVal] tfeat-                              `catchError` (\_ -> throwError enrichErr)-           let newnode = if eqTop then a {gup   = newfeat}-                                  else a {gdown = newfeat}-           return $ fixNode newnode $ replace sub t- where-   (eqName, eqTop, eqAtt) = eqLhs-   fixNode n mt = mt { tree = repNodeByNode (matchNodeName eqName) n (tree mt) }-   enrichErr = EnrichError { eeMacro    = t-                           , eeLexEntry = lexEntry-                           , eeLocation = eqLhs }--pathEqName :: PathEqPair -> String-pathEqName = fst3.fst--missingCoanchors :: ILexEntry -> MTtree -> [String]-missingCoanchors lexEntry t =-  -- list monad-  do eq <- nubBy ((==) `on` pathEqName) $ snd $ lexEquations lexEntry-     let name = pathEqName eq-     case seekCoanchor name t of-       Nothing -> [name]-       Just _  -> []---- | Split a lex entry's path equations into interface enrichement equations---   or (co-)anchor modifiers-lexEquations :: ILexEntry -> ([PathEqPair], [PathEqPair])-lexEquations =-  partition (nameIs "interface") . map parseAv . iequations-  where-   parseAv (AvPair a v) =-    case parsePathEq a of-      Left (err,peq) -> unsafePerformIO $ do putStrLn err-                                             return (peq,v)-      Right peq -> (peq, v)-   nameIs n x = pathEqName x == n--seekCoanchor :: String -> MTtree -> Maybe GNode-seekCoanchor eqName t =- case filterTree (matchNodeName eqName) (tree t) of- [a] -> Just a- []  -> Nothing- _   -> geniBug $ "Tree with multiple matches in enrichBy. " ++-                  "\nTree: " ++ pidname t ++ "\nFamily: " ++ pfamily t ++-                  "\nMatching on: " ++ eqName--matchNodeName :: String -> GNode -> Bool-matchNodeName "anchor" = ganchor-matchNodeName n        = (== n) . gnname---- | Parse a path equation using the GenI conventions---   This always succeeds, but can return @Just warning@---   if anything anomalous comes up-parsePathEq :: String -> Either (String,PathEqLhs) (PathEqLhs)-parsePathEq e =-  case wordsBy (== '.') e of-  (n:"top":r) -> Right (n, True, rejoin r)-  (n:"bot":r) -> Right (n, False, rejoin r)-  ("top":r) -> Right ("anchor", True, rejoin r)-  ("bot":r) -> Right ("anchor", False, rejoin r)-  ("anc":r) -> parsePathEq $ rejoin $ "anchor":r-  ("anchor":r)    -> Right ("anchor", False, rejoin r)-  ("interface":r) -> Right ("interface", False, rejoin r)-  (n:r) -> Left (err, (n, True, rejoin r))-           where err = "Warning: Interpreting path equation " ++ e ++-                       " as applying to top of " ++ n ++ "."-  _ -> Left (err, ("", True, e))-       where err = "Warning: could not interpret path equation " ++ e- where-  rejoin = concat . intersperse "."-\end{code}--\subsubsection{Lemanchor mechanism}--One problem in building reversible grammars is the treatment of co-anchors.-In the French language, for example, we have some structures like-\natlang{C'est Jean qui regarde Marie}-\natlang{It is John who looks at Mary}--One might be tempted to hard code the ce (it) and the être (is) into the tree-for regarder (look at), something like \texttt{s(ce, être, n$\downarrow$, qui,-v(regarder), n$\downarrow$)}.  Indeed, this would work just fine for-generation, but not for parsing.  When you parse, you would encounter inflected-forms for these items for example \natlang{c'} for \natlang{ce} or-\natlang{sont} or \natlang{est} for \natlang{être}.  Hard-coding the \natlang{ce}-into such trees would break parsing.--To work around this, we propose a mechanism to have our co-anchors and parsing-too. Co-anchors that are susceptible to morphological variation should be-\begin{itemize}-\item marked in a substitution site (this is to keep parsers happy)-\item have a feature \texttt{bot.lemanchor:foo} where foo is the-      coanchor you want-\end{itemize}--GenI will convert these into non-substitution sites with a lexical item-leaf node.--\begin{code}-setLemAnchors :: Tree GNode -> Tree GNode-setLemAnchors t =- repAllNode fn filt t- where-  filt (Node a []) = gtype a == Subs && (isJust. lemAnchor) a-  filt _ = False-  fn (Node x k) = setLexeme (lemAnchorMaybeFake x) $-                    Node (x { gtype = Other, gaconstr = False }) k-  ---  lemAnchorMaybeFake :: GNode -> [String]-  lemAnchorMaybeFake n =-    case lemAnchor n of-    Nothing -> ["ERR_UNSET_LEMMANCHOR"]-    Just l  -> l-  lemAnchor :: GNode -> Maybe [String]-  lemAnchor n =-    case [ v | AvPair a v <- gdown n, a == _lemanchor ] of-    [GConst l] -> Just l-    _          -> Nothing--_lemanchor :: String-_lemanchor = "lemanchor"-\end{code}--\subsubsection{Node origins}--After lexical selection, we label each tree node with its origin, most-likely the name and id of its elementary tree.  This is useful for-building derivation trees--\begin{code}-setOrigin :: String -> Tree GNode -> Tree GNode-setOrigin t = fmap (\g -> g { gorigin = t })-\end{code}--% ---------------------------------------------------------------------\subsection{Pre-selection and pre-anchoring}-\label{sec:pre-anchor}-% ----------------------------------------------------------------------For testing purposes, we can perform lexical selection ahead of time and store-it somewhere else.--\begin{code}--- | Only used for instances of GenI where the grammar is compiled---   directly into GenI.-type Selector = ProgStateRef -> IO ([TagElem],[ILexEntry])--defaultSelector :: Selector-defaultSelector = runLexSelection-\end{code}--For debugging purposes, it is often useful to perform lexical selection and-surface realisation separately.  Pre-anchored mode allows the user to just-pass the lexical selection in as a file of anchored trees associated with a-semantics.--\begin{code}-readPreAnchored :: ProgState -> IO [TagElem]-readPreAnchored pst =- case getFlagP MacrosFlg (pa pst) of- Nothing   -> fail "No macros file specified (preanchored mode)"- Just file -> parseFromFileOrFail geniTagElems file-\end{code}--% ---------------------------------------------------------------------% Boring utility code-% ----------------------------------------------------------------------\ignore{-\begin{code}-instance JSON GeniResult where- readJSON j =-    do jo <- fromJSObject `fmap` readJSON j-       let field x = maybe (fail $ "Could not find: " ++ x) readJSON-                   $ lookup x jo-       GeniResult <$> field "raw"-                  <*> field "realisations"-                  <*> field "derivation"-                  <*> field "lexical-selection"-                  <*> field "ranking"-                  <*> field "violations"-                  <*> field "result-type"- showJSON nr =-     JSObject . toJSObject $ [ ("raw", showJSON $ grLemmaSentence nr)-                             , ("realisations", showJSONs $ grRealisations nr)-                             , ("derivation", showJSONs $ grDerivation nr)-                             , ("lexical-selection", showJSONs $ grLexSelection nr)-                             , ("ranking", showJSON $ grRanking nr)-                             , ("violations", showJSONs $ grViolations nr)-                             , ("result-type", showJSON $ grResultType nr)-                             ]--instance JSON ResultType where-  readJSON j =-    do js <- fromJSString `fmap` readJSON j-       case js of-         "partial"   -> return PartialResult-         "complete"  -> return CompleteResult-         ty          -> fail $ "unknown result type: " ++ ty-  showJSON CompleteResult = JSString $ toJSString "complete"-  showJSON PartialResult  = JSString $ toJSString "partial"--instance JSON GeniLexSel where- readJSON j =-    do jo <- fromJSObject `fmap` readJSON j-       let field x = maybe (fail $ "Could not find: " ++ x) readJSON-                   $ lookup x jo-       GeniLexSel <$> field "lex-item"-                  <*> field "trace"- showJSON x =-     JSObject . toJSObject $ [ ("lex-item", showJSON  $ nlTree x)-                             , ("trace",    showJSONs $ nlTrace x)-                             ]-\end{code}-}-
− src/NLP/GenI/GeniParsers.lhs
@@ -1,919 +0,0 @@-% GenI surface realiser-% Copyright (C) 2005 Carlos Areces and Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.--\chapter{File formats}-\label{cha:formats}-\label{cha:GeniParsers}--This chapter is a description of the file formats used by \geni.  We'll be-using EBNFs to describe the format below.   Here are some rules and types of-rules we leave out, and prefer to describe informally:--\begin{verbatim}-<alpha-numeric>-<string-literal> (stuff between quotes)-<opt-whatever> (systematically... "" | <whatever>)-<keyword-whatever> (systematically.. "whatever" ":")-\end{verbatim}--\ignore{-\begin{code}-module NLP.GenI.GeniParsers (-  -- * Test suites-  geniTestSuite, geniSemanticInput, geniTestSuiteString,-  geniDerivations,-  toSemInputString,-  -- * Trees-  geniMacros, geniTagElems,-  -- * Lexicon and morph-  geniLexicon, geniMorphInfo,-  -- * Basics-  geniFeats, geniPolarities, geniSemantics, geniValue, geniWords,-  -- * Helpers-  geniWord, geniLanguageDef, tillEof,-  ---  parseFromFile, -- UTF-8 version-  module Text.ParserCombinators.Parsec-) where--import NLP.GenI.General ((!+!), Interval, ival)-import NLP.GenI.Btypes-import NLP.GenI.Tags (TagElem(..), emptyTE, setTidnums)-import NLP.GenI.GeniShow (GeniShow(geniShow))-import NLP.GenI.PolarityTypes--import Control.Monad (liftM, when)-import Data.List (sort)-import qualified Data.Map  as Map-import qualified Data.Tree as T-import Text.ParserCombinators.Parsec hiding (parseFromFile)-import Text.ParserCombinators.Parsec.Language (emptyDef)-import Text.ParserCombinators.Parsec.Token (TokenParser,-    LanguageDef(..), makeTokenParser)-import qualified Text.ParserCombinators.Parsec.Token as P-import qualified System.IO.UTF8 as UTF8--\end{code}-}--\section{General notes}--\subsection{Comments}--Any \geni format file can include comments.  Comments start \verb!%!.-There is also the option of using \verb'/* */' for embedded comments.--\subsection{Reserved words}--The following are reserved words.  You should not use them as variable names.-NB: the reserved words are indicated below between quotes; eg.  ``semantics''.-You can ignore C pre-processor noise such as \verb!#define SEMANTICS!--\begin{includecodeinmanual}-\begin{code}--- reserved words-#define SEMANTICS       "semantics"-#define SENTENCE        "sentence"-#define OUTPUT          "output"-#define TRACE           "trace"-#define ANCHOR          "anchor"-#define SUBST           "subst"-#define FOOT            "foot"-#define LEX             "lex"-#define TYPE            "type"-#define ACONSTR_NOADJ   "aconstr:noadj"-#define INITIAL         "initial"-#define AUXILIARY       "auxiliary"-#define IDXCONSTRAINTS  "idxconstraints"-#define BEGIN           "begin"-#define END             "end"-\end{code}-\end{includecodeinmanual}--\subsection{Lexer}--For reference, we include the Parsec LanguageDef that we use to implement-the \geni format.--\begin{includecodeinmanual}-\begin{code}-geniLanguageDef :: LanguageDef ()-geniLanguageDef = emptyDef-         { commentLine = "%"-         , commentStart = "/*"-         , commentEnd = "*/"-         , opLetter = oneOf ""-         , reservedOpNames = [""]-         , reservedNames =-             [ SEMANTICS , SENTENCE, OUTPUT, IDXCONSTRAINTS, TRACE-             , ANCHOR , SUBST , FOOT , LEX , TYPE , ACONSTR_NOADJ-             , INITIAL , AUXILIARY-             , BEGIN , END ]-         , identLetter = identStuff-         , identStart  = identStuff-         }-  where identStuff = alphaNum <|> oneOf "_'+-."-\end{code}-\end{includecodeinmanual}--\section{The basics}--\subsection{Variables and constants}--Below are some examples of \geni variables and constants.  Note that we support-atomic disjunction of constants, as in \verb!Foo|bar|baz!, but not variables.--\begin{center}-\begin{tabular}{ll}-anonymous variable & \verb!?_! or \verb!_! \\-variables & \verb!Foo!, \verb!?X! or \verb!?x! \\-constants & \verb!Foo!, \verb!foo!, \verb!X!, \verb!x! or \verb!Foo|bar! \\-\end{tabular}-\end{center}--Here is an EBNF for GenI variables and constants--\begin{SaveVerbatim}{KoweyTmp}-<value>         ::= <variable> | <anonymous-variable> | <constant-disj>-<variable>      ::= "?" <identifier>-<anonymous>     ::= "?_" | "_"-<constant-disj> ::= <constant> (| <constant>)*-<constant>      ::= <identifier>-<identifier>    ::= <alphanumeric> | "+" | "-" | "_"-\end{SaveVerbatim}-\begin{center}-\fbox{\BUseVerbatim{KoweyTmp}}-\end{center}--\begin{code}-geniValue :: Parser GeniVal-geniValue =   ((try $ anonymous) <?> "_ or ?_")-          <|> (constants  <?> "a constant or atomic disjunction")-          <|> (variable   <?> "a variable")-  where-    question = "?"-    ---    constants :: Parser GeniVal-    constants =-      do c <- sepBy1 (looseIdentifier <|> stringLiteral) (symbol "|")-         return (GConst c)-    variable :: Parser GeniVal-    variable =-      do symbol question-         v <- identifier-         return (GVar v)-    anonymous :: Parser GeniVal-    anonymous =-      do optional $ symbol question-         symbol "_"-         return GAnon-\end{code}--\subsection{Feature structures}--In addition to variables and constants, \geni also makes heavy use of flat-feature structures.  They take the form \verb![foo:bar ping:?Pong]!, or more-formally,--\begin{SaveVerbatim}{KoweyTmp}-<feature-structure>      ::= "[" <atttribute-value-pair>* "]"-<attribute-value-pair>   ::= <identifier-or-reserved> ":" <value>-<identifier-or-reserved> ::= <identifier> | <reserved>-\end{SaveVerbatim}-\begin{center}-\fbox{\BUseVerbatim{KoweyTmp}}-\end{center}--\begin{code}-geniFeats :: Parser Flist-geniFeats = option [] $ squares $ many geniAttVal--geniAttVal :: Parser AvPair-geniAttVal = do-  att <- identifierR <?> "an attribute"; colon-  val <- geniValue <?> "a GenI value"-  return $ AvPair att val-\end{code}--\subsection{Semantics}-\label{sec:geni-semantics}--A \jargon{semantics} is basically a set of literals.  Semantics are used in-to provide \geni input (section \ref{sec:geni-input-semantics}) and in the-definition of lexical entries (section \ref{sec:geni-lexicon}).--Notice that this is a flat semantic representation!  No literals within-literals, please.  A literal can take one of two forms:-\begin{verbatim}-  handle:predicate(arguments)-         predicate(arguments)-\end{verbatim}--The arguments are space-delimited.  Not providing a handle is-equivalent to providing an anonymous one.--\begin{SaveVerbatim}{KoweyTmp}-<semantics>      ::= <keyword-semantics> "[" <literal>* "]"-<literal>        ::= <identifier> "(" <value>* ")"-\end{SaveVerbatim}-\begin{center}-\fbox{\BUseVerbatim{KoweyTmp}}-\end{center}--\begin{code}-geniSemantics :: Parser Sem-geniSemantics =-  do sem <- many (geniLiteral <?> "a literal")-     return (sortSem sem)--geniLiteral :: Parser Pred-geniLiteral =-  do handle    <- option GAnon handleParser <?> "a handle"-     predicate <- geniValue <?> "a predicate"-     pars      <- parens (many geniValue) <?> "some parameters"-     ---     return (handle, predicate, pars)-  where handleParser =-          try $ do { h <- geniValue ; char ':' ; return h }-\end{code}--\section{Semantic inputs and test suites}-\label{sec:geni-input-semantics}--\subsection{Semantic input}--The semantic input can either be provided directly in the graphical interface-or as part of a test suite.--The format for semantic inputs is actually a bit richer than the core-definition in section \ref{sec:geni-semantics}, but I have not yet written the-documentation for it.--\textbf{TODO}: The semantics may contain literal based constraints as described-in section \ref{sec:fixme}.  These constraints are just a space-delimited list-of String.  When returning the results, we separate them out from the semantics-proper so that they can be treated separately.  Index constraints are-represented as feature structures.--\begin{code}-geniSemanticInput :: Parser (Sem,Flist,[LitConstr])-geniSemanticInput =-  do keywordSemantics-     (sem,litC) <- liftM unzip $ squares $ many literalAndConstraint-     idxC       <- option [] geniIdxConstraints-     ---     let sem2     = createHandles sem-         semlitC2 = [ (s,c) | (s,c) <- zip sem2 litC, (not.null) c ]-     return (createHandles sem, idxC, semlitC2)-  where-     -- set all anonymous handles to some unique value-     -- this is to simplify checking if a result is-     -- semantically complete-     createHandles :: Sem -> Sem-     createHandles = zipWith setHandle ([1..] :: [Int])-     ---     setHandle i (h, pred_, par) =-       let h2 = if h /= GAnon then h-                else GConst ["genihandle" ++ (show i)]-       in (h2, pred_, par)-     ---     literalAndConstraint :: Parser (Pred, [String])-     literalAndConstraint =-       do l <- geniLiteral-          t <- option [] $ squares $ many identifier-          return (l,t)---- | The original string representation of the semantics (for gui)-geniSemanticInputString :: Parser String-geniSemanticInputString =- do keywordSemantics-    s <- squaresString-    whiteSpace-    optional geniIdxConstraints-    return s--geniIdxConstraints :: Parser Flist-geniIdxConstraints = keyword IDXCONSTRAINTS >> geniFeats--squaresString :: Parser String-squaresString =- do char '['-    s <- liftM concat $ many $ (many1 $ noneOf "[]") <|> squaresString-    char ']'-    return $ "[" ++ s ++ "]"---- the output end of things--- displaying preformatted semantic input--data SemInputString = SemInputString String Flist--instance GeniShow SemInputString where- geniShow (SemInputString semStr idxC) =-   SEMANTICS ++ ":" ++ semStr ++ (if null idxC then "" else r)-   where r = "\n" ++ IDXCONSTRAINTS ++ ": " ++ showFlist idxC--toSemInputString :: SemInput -> String -> SemInputString-toSemInputString (_,lc,_) s = SemInputString s lc-\end{code}--\subsection{Test suite}--\geni accepts an entire test suite of semantic inputs that you can choose from.-The test suite entries can be named.  In fact, it is probably a good idea to do-so, because the names are often shorter than the expected output, and easier to-read than the semantics.  Note the expected output isn't used by \geni itself,-but external tools that ``test'' \geni.--\begin{SaveVerbatim}{KoweyTmp}-<test-suite>       ::= <test-suite-entry>*-<test-suite-entry> ::= <opt-identifier> <semantics> <expected-output>*-<expected-output>  ::= <opt-keyword-sentence> "[" <identifier>* "]"-\end{SaveVerbatim}-\begin{center}-\fbox{\BUseVerbatim{KoweyTmp}}-\end{center}--\begin{code}-geniTestSuite :: Parser [TestCase]-geniTestSuite =-  tillEof (many geniTestCase)---- | Just the String representations of the semantics---   in the test suite-geniTestSuiteString :: Parser [String]-geniTestSuiteString =-  tillEof (many geniTestCaseString)---- | This is only used by the script genimakesuite-geniDerivations :: Parser [TestCaseOutput]-geniDerivations = tillEof $ many geniOutput--geniTestCase :: Parser TestCase-geniTestCase =-  do name  <- option "" (identifier <?> "a test case name")-     seminput <- geniSemanticInput-     sentences <- many geniSentence-     outputs   <- many geniOutput-     return $ TestCase name "" seminput sentences outputs---- note that the keyword is NOT optional-type TestCaseOutput = (String, Map.Map (String,String) [String])-geniOutput :: Parser TestCaseOutput-geniOutput =- do ws <- keyword OUTPUT >> (squares geniWords)-    ds <- Map.fromList `fmap` many geniTraces-    return (ws, ds)--geniTraces :: Parser ((String,String), [String])-geniTraces =- do keyword TRACE-    squares $ do-      k1 <- withWhite geniWord-      k2 <- withWhite geniWord-      whiteSpace >> char '!' >> whiteSpace-      traces <- sepEndBy1 geniWord whiteSpace-      return ((k1,k2), traces)--withWhite :: Parser a -> Parser a-withWhite p = p >>= (\a -> whiteSpace >> return a)--geniSentence :: Parser String-geniSentence = optional (keyword SENTENCE) >> squares geniWords--geniWords :: Parser String-geniWords =- unwords `fmap` (sepEndBy1 geniWord whiteSpace <?> "a sentence")--geniWord :: Parser String-geniWord = many1 (noneOf "[]\v\f\t\r\n ")---- | The original string representation of a test case semantics---   (for gui)-geniTestCaseString :: Parser String-geniTestCaseString =- do option "" (identifier <?> "a test case name")-    s <- geniSemanticInputString-    many geniSentence-    many geniOutput-    return s-\end{code}--\section{Lexicon}-\label{sec:geni-lexicon}--The lexicon associates semantic entries with lemmas and trees.--\subsection{Lexicon examples}--There are two ways to write the lexicon.  We show the old (deprecated)-way first because most of the examples are still written in this style.--\paragraph{Example 1 (deprecated)}--\begin{verbatim}-le clitic (?I)-semantics:[]--le Det (?I)-semantics:[def(?I)]--livre nC (?I)-semantics:[book(?I)]--persuader vArity3 (?E ?X ?Y ?Z)-semantics:[?E:convince(?X ?Y ?Z)]--persuader v vArity3controlObj-semantics:[?E:convince(?X ?Y ?Z)]-\end{verbatim}--\paragraph{Example 2 (preferred)}--\begin{verbatim}-detester n0Vn1-equations:[theta1:agent theta2:patient arg1:?X arg2:?Y evt:?L]-filters:[family:n0Vn1]-semantics:[?E:hate(?L) ?E:agent(?L ?X) ?E:patient(?L ?Y)]-\end{verbatim}--\subsection{Notes about lexicons}--\begin{itemize}-\item The semantics associated with a lexicali item may have more than one literal-\begin{verbatim}-cher adj (?E ?X ?Y)-semantics:[?E:cost(?X ?Y) ?E:high(?Y)]-\end{verbatim}--\item A lemma may have more than one distinct semantics-\begin{verbatim}-bank n (?X)-semantics:[bank(?X)]--bank v (?E ?X ?D)-semantics:[?E:lean(?X,?D)]-\end{verbatim}--\item A semantics may be realised by more than one lexical entry (e.g.  synonynms)-\begin{verbatim}-livre nC (?I)-semantics:[book(?I)]--bouquin nC (?I)-semantics:[book(?I)]-\end{verbatim}-\end{itemize}--\subsection{Lexicon EBNF}--\begin{SaveVerbatim}{KoweyTmp}-<lexicon>        ::= <lexicon-entry>*-<lexicon-entry>  ::= <lexicon-header> <opt-filters> <semantics>-<lexicon-header> ::= <lemma> <family> <parameters>-                   | <lemma> <family> <keyword-equations> <feature-structure>-<parameters>     ::= "(" <value>* <opt-interface> ")"-<interface>      ::= "!" <attribute-value-pairs>*-<filters>        ::= <keyword-filter> <feature-structure>-\end{SaveVerbatim}-\begin{center}-\fbox{\BUseVerbatim{KoweyTmp}}-\end{center}--\begin{code}-geniLexicon :: Parser [ILexEntry]-geniLexicon = tillEof $ many1 geniLexicalEntry--geniLexicalEntry :: Parser ILexEntry-geniLexicalEntry =-  do lemma  <- (looseIdentifier <|> stringLiteral) <?> "a lemma"-     family <- identifier <?> "a tree family"-     (pars, interface) <- option ([],[]) $ parens paramsParser-     equations <- option [] $ do keyword "equations"-                                 geniFeats <?> "path equations"-     filters <- option [] $ do keyword "filters"-                               geniFeats-     keywordSemantics-     (sem,pols) <- squares geniLexSemantics-     ---     return emptyLE { iword = [lemma]-                    , ifamname = family-                    , iparams = pars-                    , iinterface = sortFlist interface-                    , iequations = equations-                    , ifilters = filters-                    , isemantics = sem-                    , isempols = pols }-  where-    paramsParser :: Parser ([GeniVal], Flist)-    paramsParser = do-      pars <- many geniValue <?> "some parameters"-      interface <- option [] $ do symbol "!"-                                  many geniAttVal-      return (pars, interface)--geniLexSemantics :: Parser (Sem, [[Int]])-geniLexSemantics =-  do litpols <- many (geniLexLiteral <?> "a literal")-     return $ unzip litpols--geniLexLiteral :: Parser (Pred, [Int])-geniLexLiteral =-  do (handle, hpol) <- option (GAnon,0) (handleParser <?> "a handle")-     predicate  <- geniValue <?> "a predicate"-     paramsPols <- parens (many geniPolValue) <?> "some parameters"-     ---     let (pars, pols) = unzip paramsPols-         literal = (handle, predicate, pars)-     return (literal, hpol:pols)-  where handleParser =-          try $ do { h <- geniPolValue; colon; return h }--geniPolValue :: Parser (GeniVal, Int)-geniPolValue =-  do p <- geniPolarity-     v <- geniValue-     return (v,p)-\end{code}--\section{Tree schemata}--The tree schemata file (for historical reasons, this is also called the macros-file) contains a set of unlexicalised trees organised into families.  Such-``macros'' consist of a--\begin{enumerate}-\item a family name and (optionally) a macro name-\item a list of parameters-\item ''initial'' or ''auxiliary''-\item a tree.-\end{enumerate}--\subsection{Trees}--\jargon{Trees} are recursively defined structure of form \verb!node{tree*}!-For example, in the table below, the  structure on the left should produce the-tree on the right:--\begin{SaveVerbatim}{KoweyTmp}-n1{-   n2-   n3{-      n4-      n5-     }-   n6-}-\end{SaveVerbatim}-\begin{tabular}{ll}-\BUseVerbatim{KoweyTmp} & \includegraphics[scale=0.50]{images/tree-format-example.png} \\-\end{tabular}--\subsection{Nodes}--\jargon{Nodes} consist of-\begin{enumerate}-\item a name-\item a type (optional)-\item either a lexeme, or top and bottom feature structures. Here are examples of the five possible kinds of nodes:-\end{enumerate}--\noindent-Here are some examples of nodes-\begin{verbatim}- n1 [cat:n idx:?I]![cat:n idx:?I]            % basic- n3 type:subst [cat:n idx:?Y]![cat:n idx:?Y] % subst- n4 type:foot  [cat:n idx:?Y]![cat:n idx:?Y] % foot- n5 type:lex   "de"                        % coanchor- n2 anchor                                 % anchor- n5 aconstr:noadj % node with a null-adjunction constraint (other than subst or foot)-\end{verbatim}--\subsection{Example}--\begin{verbatim}-adj:post(?I)  auxiliary-n0[cat:n idx:?I det:_]![cat:n idx:?I det:minus ]-{-  n1 type:foot [cat:n idx:?I det:minus]![cat:n idx:?I det:minus]-  n2[cat:a]![]-  {-    n3 anchor-  }-}--adj:pre(?I)  auxiliary-n0[cat:n idx:?I det:_ qu:_]![cat:n idx:?I det:minus ]-{-  n1[cat:a]![]-  {-    n2 anchor-  }-  n3 type:foot [cat:n idx:?I det:minus]![cat:n idx:?I det:minus]-}--vArity2:n0vn1(?E ?X ?Y) initial-n1[cat:p]![]-{-  n2 type:subst [cat:n idx:?X det:plus]![cat:n idx:?X]-  n3[cat:v idx:?E]![]-  {-    n4 anchor-  }-  n5 type:subst [cat:n idx:?Y det:plus]![cat:n idx:?Y]-}-\end{verbatim}--\subsection{EBNF}--\begin{SaveVerbatim}{KoweyTmp}-<macros> ::= <macro>*-<macro>  ::= <family-name> <opt-macro-name> <parameters> <tree-type> <tree>-             <opt-semantics> <opt-trace>--<parameters>     ::= "(" <value>* <opt-interface> ")"-<interface>      ::= ! <attribute-value-pair>*-<macro-name>     ::= <identifier>-<tree-type>      ::= "initial" | "auxiliary"-<trace>          ::= <keyword-trace> "[" <identifier>* "]"--<tree>           ::= <node> | <node> "{" <tree>* "}"-<node>           ::= <node-name> <opt-node-type> <node-payload>-<node-name>      ::= <identifier>-<node-type>      ::= <keyword-type> <core-node-type> | "anchor"-<core-node-type> ::= "foot" | "subst" | "lex"-<node-payload>   ::= <string-literal> | <feature-structure> "!" <feature-structure>-\end{SaveVerbatim}-\begin{center}-\fbox{\BUseVerbatim{KoweyTmp}}-\end{center}--\begin{code}-geniMacros :: Parser [MTtree]-geniMacros = tillEof $ many geniTreeDef--initType, auxType :: Parser Ptype-initType = do { reserved INITIAL ; return Initial  }-auxType  = do { reserved AUXILIARY ; return Auxiliar }--geniTreeDef :: Parser MTtree-geniTreeDef =-  do sourcePos <- getPosition-     family   <- identifier-     tname    <- option "" $ do { colon; identifier }-     (pars,iface)   <- geniParams-     theTtype  <- (initType <|> auxType)-     theTree  <- geniTree-     -- sanity checks?-     let treeFail x =-          do setPosition sourcePos -- FIXME does not do what I expect-             fail $ "In tree " ++ family ++ ":" ++ tname ++ " " ++ show sourcePos ++ ": " ++ x-     let theNodes = T.flatten theTree-         numFeet    = length [ x | x <- theNodes, gtype x == Foot ]-         numAnchors = length [ x | x <- theNodes, ganchor x ]-     when (not $ any ganchor theNodes) $-       treeFail "At least one node in an LTAG tree must be an anchor"-     when (numAnchors > 1) $-       treeFail "There can be no more than 1 anchor node in a tree"-     when (numFeet > 1) $-       treeFail "There can be no more than 1 foot node in a tree"-     when (theTtype == Initial && numFeet > 0) $-       treeFail "Initial trees may not have foot nodes"-     ---     psem     <- option Nothing $ do { keywordSemantics; liftM Just (squares geniSemantics) }-     ptrc     <- option [] $ do { keyword TRACE; squares (many identifier) }-     ---     return TT{ params = pars-              , pfamily = family-              , pidname = tname-              , pinterface = sortFlist iface-              , ptype = theTtype-              , tree = theTree-              , ptrace = ptrc-              , psemantics = psem-              }--geniTree :: Parser (T.Tree GNode)-geniTree =-  do node <- geniNode-     kids <- option [] (braces $ many geniTree)-             <?> "child nodes"-     -- sanity checks-     let noKidsAllowed t c = when (c node && (not.null $ kids)) $-             fail $ t ++ " nodes may *not* have any children"-     noKidsAllowed "Anchor"       $ ganchor-     noKidsAllowed "Substitution" $ (== Subs) . gtype-     noKidsAllowed "Foot"         $ (== Foot) . gtype-     ---     return (T.Node node kids)--geniNode :: Parser GNode-geniNode =-  do name      <- identifier-     nodeType  <- option "" ( (keyword TYPE >> typeParser)-                              <|>-                              reserved ANCHOR)-     lex_   <- if nodeType == LEX-                  then (sepBy (stringLiteral<|>identifier) (symbol "|") <?> "some lexemes")-                  else return []-     constr <- case nodeType of-               ""     -> adjConstraintParser-               ANCHOR -> adjConstraintParser-               _  -> return True-     (top_,bot_) <- -- features only obligatory for non-lex nodes-                    if nodeType == LEX-                       then option ([],[]) $ try topbotParser-                       else topbotParser-     ---     let top   = sort top_-         bot   = sort bot_-         nodeType2 = case nodeType of-                       ANCHOR  -> Lex-                       LEX     -> Lex-                       FOOT    -> Foot-                       SUBST   -> Subs-                       ""        -> Other-                       other     -> error ("unknown node type: " ++ other)-     return $ GN { gnname = name, gtype = nodeType2-                 , gup = top, gdown = bot-                 , glexeme  = lex_-                 , ganchor  = (nodeType == ANCHOR)-                 , gaconstr = constr-                 , gorigin  = "" }-  where-    typeParser = choice $ map (try.symbol) [ ANCHOR, FOOT, SUBST, LEX ]-    adjConstraintParser = option False $ reserved ACONSTR_NOADJ >> return True-    topbotParser =-      do top <- geniFeats <?> "top features"-         symbol "!"-         bot <- geniFeats <?> "bot features"-         return (top,bot)---- | This makes it possible to read anchored trees, which may be---   useful for debugging purposes.------   FIXME: note that this is very rudimentary; we do not set id numbers,---   parse polarities. You'll have to call---   some of our helper functions if you want that functionality.-geniTagElems :: Parser [TagElem]-geniTagElems = tillEof $ setTidnums `fmap` many geniTagElem--geniTagElem :: Parser TagElem-geniTagElem =- do family   <- identifier-    tname    <- option "" $ do { colon; identifier }-    iface    <- (snd `liftM` geniParams) <|> geniFeats-    theType  <- initType <|> auxType-    theTree  <- geniTree-    sem      <- do { keywordSemantics; squares geniSemantics }-    ---    return $ emptyTE { idname = tname-                     , ttreename = family-                     , tinterface = iface-                     , ttype  = theType-                     , ttree = theTree-                     , tsemantics = sem }---- | 'geniParams' recognises a list of parameters optionally followed by a---  bang (\verb$!$) and a list of attribute-value pairs.  This whole thing is---  to wrapped in the parens.------  TODO: deprecate-geniParams :: Parser ([GeniVal], Flist)-geniParams = parens $ do-  pars <- many geniValue <?> "some parameters"-  interface <- option [] $ do { symbol "!"; many geniAttVal }-  return (pars, interface)-\end{code}--\section{Morphology}--A morphinfo file associates predicates with morphological feature structures.-Each morphological entry consists of a predicate followed by a feature-structuer.  For more information, see chapter \ref{cha:Morphology}.-(\textbf{TODO}: describe format)--\begin{code}-geniMorphInfo :: Parser [(String,Flist)]-geniMorphInfo = tillEof $ many morphEntry--morphEntry :: Parser (String,Flist)-morphEntry =-  do pred_ <- identifier-     feats <- geniFeats-     return (pred_, feats)-\end{code}--% ======================================================================-% everything else-% ======================================================================--\begin{code}--- ------------------------------------------------------------------------- polarities--- -----------------------------------------------------------------------geniPolarities :: Parser (Map.Map PolarityKey Interval)-geniPolarities = tillEof $ toMap `fmap` many pol-  where-    toMap = Map.fromListWith (!+!)-    pol = do p <- geniPolarity-             i <- identifier-             return (PolarityKey i,ival p)---- | 'geniPolarity' associates a numerical value to a polarity symbol,---  that is, '+' or '-'.-geniPolarity :: Parser Int-geniPolarity = option 0 (plus <|> minus)-  where-    plus  = do { char '+'; return  1   }-    minus = do { char '-'; return (-1) }---- ------------------------------------------------------------------------- keyword--- ------------------------------------------------------------------------{-# INLINE keyword #-}-keyword :: String -> Parser String-keyword k =-  do let helper = try $ do { reserved k; colon; return k }-     helper <?> k ++ ":"--{-# INLINE keywordSemantics #-}-keywordSemantics :: Parser String-keywordSemantics = keyword SEMANTICS---- ------------------------------------------------------------------------- language def helpers--- ------------------------------------------------------------------------lexer :: TokenParser ()-lexer  = makeTokenParser geniLanguageDef--whiteSpace :: CharParser () ()-whiteSpace = P.whiteSpace lexer--looseIdentifier, identifier, stringLiteral, colon :: CharParser () String-identifier    = P.identifier lexer---- stolen from Parsec code (ident)--- | Like 'identifier' but allows for reserved words too-looseIdentifier =- do { i <- ident ; whiteSpace; return i }- where-  ident =-   do { c <- identStart geniLanguageDef-      ; cs <- many (identLetter geniLanguageDef)-      ; return (c:cs) } <?> "identifier"--stringLiteral = P.stringLiteral lexer-colon         = P.colon lexer--squares, braces, parens :: CharParser () a -> CharParser () a-squares = P.squares lexer-braces  = P.braces  lexer-parens  = P.parens  lexer--reserved, symbol :: String -> CharParser () String-reserved s = P.reserved lexer s >> return s-symbol = P.symbol lexer---- ------------------------------------------------------------------------- parsec helpers--- -------------------------------------------------------------------------- | identifier, permitting reserved words too-identifierR :: CharParser () String-identifierR-  = do { c <- P.identStart geniLanguageDef-       ; cs <- many (P.identLetter geniLanguageDef)-       ; return (c:cs)-       }-       <?> "identifier or reserved word"--tillEof :: Parser a -> Parser a-tillEof p =-  do whiteSpace-     r <- p-     eof-     return r---- stolen from Parsec and adapted to use UTF-8 input-parseFromFile :: Parser a -> SourceName -> IO (Either ParseError a)-parseFromFile p fname-    = do{ input <- UTF8.readFile fname-        ; return (parse p fname input)-        }-\end{code}
src/NLP/GenI/GeniShow.hs view
@@ -15,157 +15,55 @@ --  along with this program; if not, write to the Free Software --  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. -{--We need to be able to dump some of GenI's data structures into a simple-text format we call GeniHand.--There are at least two uses for this, one is that it allows us to-interrupt the debugging process, dump everything to file, muck around-with the trees and then pick up where we left off.--The other use is to make large grammars faster to load.  We don't actually do-this anymore, mind you, but it's nice to have the option.  The idea is to take-a massive XML grammar, parse it to a set of TagElems and then write these back-in the lighter syntax.  It's not that XML is inherently less efficient to parse-than the handwritten syntax, just that writing an efficient parser for XML-based format is more annoying, so I stuck with HaXml to make my life easy.-Unfortunately, HaXml seems to have some kind of space leak.--}- -- This module provides specialised functions for visualising tree data.+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances, TypeSynonymInstances #-}+{-# LANGUAGE OverloadedStrings #-} module NLP.GenI.GeniShow where +import Data.Text ( Text ) import Data.Tree-import Data.List(intersperse, isPrefixOf)-import qualified Data.Map as Map--import NLP.GenI.Tags- ( TagElem, idname,-   tsemantics, ttree, tinterface, ttype, ttreename,- )-import NLP.GenI.Btypes (GeniVal(GConst), AvPair(..), Ptype(..),-               Ttree(params, pidname, pfamily, pinterface, ptype, tree, psemantics, ptrace),-               GNode(..), GType(..),-               SemInput, Pred,-               TestCase(..),-               )+import qualified Data.Text as T+import NLP.GenI.Pretty +-- | GenI format; should round-trip with 'NLP.GenI.Parser' by rights+--+--   Minimal definition, either one of 'geniShow' or 'geniShowText' class GeniShow a where-  geniShow :: a -> String--instance GeniShow Ptype where- geniShow Initial  = "initial"- geniShow Auxiliar = "auxiliary"- geniShow _        = ""--instance GeniShow AvPair where- geniShow (AvPair a v) = a ++ ":" ++ geniShow v--instance GeniShow GeniVal where- geniShow (GConst xs) = concat $ intersperse "|" xs- geniShow x = show  x--instance GeniShow Pred where- geniShow (h, p, l) =-   showh ++ geniShow p ++ "(" ++ unwords (map geniShow l) ++ ")"-   where-    hideh (GConst [x]) = "genihandle" `isPrefixOf` x-    hideh _ = False-    showh = if hideh h then "" else geniShow h ++ ":"--instance GeniShow GNode where- geniShow x =-  let gaconstrstr = case (gaconstr x, gtype x) of-                    (True, Other) -> "aconstr:noadj"-                    _             ->  ""-      gtypestr n = case (gtype n) of-                     Subs -> "type:subst"-                     Foot -> "type:foot"-                     Lex  -> if ganchor n && (null.glexeme) n-                             then "type:anchor" else "type:lex"-                     _    -> ""-      glexstr n =-        if null ls then ""-        else concat $ intersperse "|" $ map quote ls-        where quote s = "\"" ++ s ++ "\""-              ls = glexeme n-      tbFeats n = (geniShow $ gup n) ++ "!" ++ (geniShow $ gdown n)-  in unwords $ filter (not.null) $ [ gnname x, gaconstrstr, gtypestr x, glexstr x, tbFeats x ]+    geniShow :: a -> String+    geniShow = T.unpack . geniShowText -instance (GeniShow a) => GeniShow [a] where- geniShow = squares . unwords . (map geniShow)+    geniShowText :: a -> Text+    geniShowText = T.pack . geniShow  instance (GeniShow a) => GeniShow (Tree a) where- geniShow t =-  let treestr i (Node a l) =-        spaces i ++ geniShow a ++-        case (l,i) of-        ([], 0)  -> "{}"-        ([], _)  -> ""-        (_, _)   -> "{\n" ++ (unlines $ map next l) ++ spaces i ++ "}"-        where next = treestr (i+1)-      ---      spaces i = take i $ repeat ' '-  in treestr 0 t--instance GeniShow TagElem where- geniShow te =-  "\n% ------------------------- " ++ idname te-  ++ "\n" ++ (ttreename te) ++ ":" ++ (idname te)-  ++ " "  ++ (geniShow.tinterface $ te)-  ++ " "  ++ (geniShow.ttype $ te)-  ++ "\n" ++ (geniShow.ttree $ te)-  ++ "\n" ++ geniShowKeyword "semantics" "" ++ (geniShow.tsemantics $ te)--instance (GeniShow a) => GeniShow (Ttree a) where- geniShow tt =-  "\n% ------------------------- " ++ pidname tt-  ++ "\n" ++ (pfamily tt) ++ ":" ++ (pidname tt)-  ++ " "  ++ (parens $    (unwords $ map geniShow $ params tt)-                       ++ " ! "-                       ++ (unwords $ map geniShow $ pinterface tt))-  ++ " "  ++ (geniShow.ptype $ tt)-  ++ "\n" ++ (geniShow.tree $ tt)-  ++ (case psemantics tt of-      Nothing   -> ""-      Just psem -> "\n" ++ geniShowKeyword "semantics" (geniShow psem))-  ++ "\n" ++ geniShowKeyword "trace" (squares.unwords.ptrace $ tt)+    geniShowText = geniShowTree 0 -instance GeniShow TestCase where- geniShow (TestCase { tcName = name-                    , tcExpected = sentences-                    , tcOutputs = outputs-                    , tcSemString = semStr-                    , tcSem = sem }) =-  unlines $ [ name, semS ]-            ++ map (geniShowKeyword "sentence" . squares) sentences-            ++ (concat.prettify.map outStuff $ outputs)+geniShowTree :: GeniShow a => Int -> Tree a -> Text+geniShowTree i (Node a l) =+    spaces <> geniShowText a <> rest   where-   semS     = if null semStr then geniShowSemInput sem "" else semStr-   prettify = if all (Map.null . snd) outputs then id else map ("":)-   gshowTrace ((k1,k2),ts) =-     geniShowKeyword "trace" . squares . showString (k1 ++ " " ++  k2 ++ " ! " ++ unwords ts) $ ""-   outStuff (o,ds) =-     [ geniShowKeyword "output"   . squares $ o ]-     ++ (map gshowTrace $ Map.toList ds)+    rest = case (l,i) of+               ([], 0) -> "{}"+               ([], _) -> ""+               (_,  _) -> "{\n" <> T.unlines (map next l)+                                <> spaces+                                <> "}"+    next   = geniShowTree (i+1)+    spaces = T.pack (replicate i ' ') +{-+geniShowSmallList :: GeniShow a => [a] -> String+geniShowSmallList = squares . unwords . (map geniShow) -parens, squares :: String -> String-parens s  = "(" ++ s ++ ")"-squares s = "[" ++ s ++ "]"+instance GeniShow [Literal] where+ geniShow = geniShowSmallList -geniShowKeyword :: String -> ShowS-geniShowKeyword k = showString k . showChar ':'+instance GeniShow (AvPair v) => GeniShow [AvPair v] where+ geniShow = geniShowSmallList -geniShowSemInput :: SemInput -> ShowS-geniShowSemInput (sem,icons,lcons) =-  let withConstraints lit =-        case concat [ cs | (p,cs) <- lcons, p == lit ] of-        [] -> geniShow lit-        cs -> geniShow lit ++ (squares . unwords $ cs)-      semStuff = geniShowKeyword "semantics" . squares-               . (showString . unwords . map withConstraints $ sem)-      idxStuff = geniShowKeyword "idxconstraints"-               . (showString . geniShow $ icons) . squares- in semStuff .  (if null icons then id else showChar '\n' . idxStuff)+-}++geniKeyword :: Text -> Text  -> Text+geniKeyword k t = k `T.append` ":" `T.append` t
src/NLP/GenI/GeniVal.hs view
@@ -16,294 +16,31 @@ -- along with this program; if not, write to the Free Software -- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. -{-# LANGUAGE OverlappingInstances, FlexibleInstances, DeriveDataTypeable #-}-module NLP.GenI.GeniVal where---- import Debug.Trace -- for test stuff-import Control.Arrow (first, (***))-import Control.Monad (liftM)-import Data.List-import Data.Maybe (fromMaybe, isJust)-import Data.Generics (Data)-import Data.Typeable (Typeable)-import qualified Data.Map as Map--import Test.HUnit-import Test.QuickCheck hiding (collect)-import Test.Framework-import Test.Framework.Providers.HUnit-import Test.Framework.Providers.QuickCheck--import Data.Generics.PlateDirect--import Control.Parallel.Strategies--import NLP.GenI.General (geniBug)--data GeniVal = GConst [String] -- ^ atomic disjunction - constant x | y | z-             | GVar   String   -- ^ variable-             | GAnon           -- ^ anonymous-  deriving (Eq,Ord, Data, Typeable)--instance Uniplate GeniVal where-  uniplate x = (Zero, \Zero -> x)--instance Show GeniVal where-  show (GConst x) = concat $ intersperse "|" x-  show (GVar x)   = '?':x-  show GAnon      = "?_"--isConst :: GeniVal -> Bool-isConst (GConst _) = True-isConst _ = False--isVar :: GeniVal -> Bool-isVar (GVar _) = True-isVar _        = False--isAnon :: GeniVal -> Bool-isAnon GAnon = True-isAnon _     = False---- | (assumes that it's a GConst!)-fromGConst :: GeniVal -> [String]-fromGConst (GConst x) = x-fromGConst x = error ("fromGConst on " ++ show x)---- | (assumes that it's a GVar!)-fromGVar :: GeniVal -> String-fromGVar (GVar x) = x-fromGVar x = error ("fromGVar on " ++ show x)---- ------------------------------------------------------------------------- Helper types--- ------------------------------------------------------------------------type Subst = Map.Map String GeniVal---- ------------------------------------------------------------------------- Unification--- -------------------------------------------------------------------------- | 'unify' performs unification on two lists of 'GeniVal'.  If---   unification succeeds, it returns @Just (r,s)@ where \verb!r! is---   the result of unification and \verb!s! is a list of substitutions that---   this unification results in.-unify :: Monad m => [GeniVal] -> [GeniVal] -> m ([GeniVal], Subst)-unify l1 l2 = repropagate `liftM` helper l1 l2- where-  repropagate (xs, sub) = (replace sub xs, sub)-  helper [] l2 = return (l2, Map.empty)-  helper l1 [] = return (l1, Map.empty)-  helper (h1:t1) (h2:t2) =-    case unifyOne h1 h2 of-    Failure -> fail $ "unification failure between " ++ show h1 ++ " and " ++ show h2-    SuccessRep v g -> prepend `liftM` helper t1b t2b-                      where-                       s   = (v,g)-                       t1b = replaceOne s t1-                       t2b = replaceOne s t2-                       prepend = (g:) *** prependToSubst s-    SuccessSans g  -> first (g:) `liftM` helper t1 t2---- | Note that the first Subst is assumed to come chronologically---   before the second one; so merging @{ X -> Y }@ and @{ Y -> 3 }@---   should give us @{ X -> 3; Y -> 3 }@;------   See 'prependToSubst' for a warning!-mergeSubst :: Subst -> Subst -> Subst-mergeSubst sm1 sm2 = Map.foldWithKey (curry prependToSubst) sm2 sm1---- | Add to variable replacement to a 'Subst' that logical comes before---   the other stuff in it.  So for example, if we have @Y -> foo@---   and we want to insert @X -> Y@, we notice that, in fact, @Y@ has---   already been replaced by @foo@, so we add @X -> foo@ instead------   Note that it is undefined if you try to append something like---   @Y -> foo@ to @Y -> bar@, because that would mean that unification---   is broken-prependToSubst :: (String,GeniVal) -> Subst -> Subst-prependToSubst (v, gr@(GVar r)) sm =-  case Map.lookup v sm of-    Just v2 -> geniBug . unlines $-                [ "prependToSubst: GenI just tried to prepend the substitution"-                , "  " ++ show (GVar v) ++ " -> " ++ show gr-                , "to one where where "-                , "  " ++ show (GVar v) ++ " -> " ++ show v2-                , "is slated to occur afterwards."-                , ""-                , "This could mean that either"-                , " (a) the core unification algorithm is broken"-                , " (b) we failed to propagate a value somewhere or"-                , " (c) we are attempting unification without renaming."-                ]-    Nothing -> Map.insert v gr2 sm-  where gr2 = fromMaybe gr $ Map.lookup r sm-prependToSubst (v, gr) sm = Map.insert v gr sm---- ------------------------------------------------------------------------- Core unification--- TODO: would continuation passing style make this more efficient?--- ------------------------------------------------------------------------data UnificationResult = SuccessSans GeniVal-                       | SuccessRep  String GeniVal-                       | Failure---- | See source code for details-unifyOne :: GeniVal -> GeniVal -> UnificationResult-unifyOne g GAnon = SuccessSans g-unifyOne GAnon g = SuccessSans g-unifyOne (GVar v) gc@(GConst _) = SuccessRep v gc-unifyOne gc@(GConst _) (GVar v) = SuccessRep v gc-unifyOne (GConst v1) (GConst v2) =-  case v1 `intersect` v2 of-    []   -> Failure-    newV -> SuccessSans (GConst newV)-unifyOne x1@(GVar v1) (GVar v2) =-  if v1 == v2-     then SuccessSans x1-     else SuccessRep  v2  x1---- ------------------------------------------------------------------------- Variable substitution--- ------------------------------------------------------------------------replace :: DescendGeniVal a => Subst -> a -> a-replace m | Map.null m = id-replace m = descendGeniVal (replaceMapG m)--replaceOne :: DescendGeniVal a => (String, GeniVal) -> a -> a-replaceOne = descendGeniVal . replaceOneG---- | Here it is safe to say (X -> Y; Y -> Z) because this would be crushed---   down into a final value of (X -> Z; Y -> Z)-replaceList :: DescendGeniVal a => [(String,GeniVal)] -> a -> a-replaceList = replace . foldl' update Map.empty-  where-   update m (s1,s2) = Map.insert s1 s2 $ Map.map (replaceOne (s1,s2)) m--replaceMapG :: Subst -> GeniVal -> GeniVal-replaceMapG m v@(GVar v_) = {-# SCC "replaceMapG" #-} Map.findWithDefault v v_ m-replaceMapG _ v = {-# SCC "replaceMapG" #-} v--replaceOneG :: (String, GeniVal) -> GeniVal -> GeniVal-replaceOneG (s1, s2) (GVar v_) | v_ == s1 = {-# SCC "replaceOneG" #-} s2-replaceOneG _ v = {-# SCC "replaceOneG" #-} v---- ------------------------------------------------------------------------- Performance--- ------------------------------------------------------------------------instance NFData GeniVal-    where rnf (GConst x1) = rnf x1-          rnf (GVar x1) = rnf x1-          rnf (GAnon) = ()---- ------------------------------------------------------------------------- Genericity--- ------------------------------------------------------------------------class DescendGeniVal a where-  descendGeniVal :: (GeniVal -> GeniVal) -> a -> a--instance DescendGeniVal GeniVal where-  descendGeniVal f = f--instance (Functor f, DescendGeniVal a) => DescendGeniVal (f a) where-  descendGeniVal = fmap . descendGeniVal---- ------------------------------------------------------------------------- Testing--- ------------------------------------------------------------------------testSuite = testGroup "unification"- [ testProperty "self" prop_unify_sym- , testProperty "anonymous variables" prop_unify_anon- , testProperty "symmetry" prop_unify_sym- , testBackPropagation- ]---- | Unifying something with itself should always succeed-prop_unify_self :: [GeniVal] -> Property-prop_unify_self x =-  (all qc_not_empty_GConst) x ==>-    case unify x x of-    Nothing  -> False-    Just unf -> fst unf == x---- | Unifying something with only anonymous variables should succeed and return---   the same result.-prop_unify_anon :: [GeniVal] -> Bool-prop_unify_anon x =-  case unify x y of-    Nothing  -> False-    Just unf -> fst unf == x-  where ---    y  = replicate (length x) GAnon---- | Unification should be symmetrical.  We can't guarantee these if there---   are cases where there are variables in the same place on both sides, so we---   normalise the sides so that this doesn't happen.-prop_unify_sym :: [GeniVal] -> [GeniVal] -> Property-prop_unify_sym x y =-  let u1 = (unify x y) :: Maybe ([GeniVal],Subst)-      u2 = unify y x-      ---      notOverlap (GVar _, GVar _) = False-      notOverlap _ = True-  in (all qc_not_empty_GConst) x &&-     (all qc_not_empty_GConst) y &&-     all (notOverlap) (zip x y) ==> u1 == u2--testBackPropagation =-  testGroup "back propagation"-   [ testCase "unify left/right" $ assertEqual "" expected $ unify left right-   , testCase "unify right/left" $ assertEqual "" expected $ unify right left-   ]- where-  n = 3-  cx = GConst ["X"]-  leftStrs = map show [1..n]-  left  = map GVar leftStrs-  right = drop 1 left ++ [cx]-  expected = Just (expectedResult, expectedSubst)-  expectedResult = replicate n cx-  expectedSubst  = Map.fromList $ zip leftStrs (repeat cx)---- ------------------------------------------------------------------------- Testing--- -------------------------------------------------------------------------- Definition of Arbitrary GeniVal for QuickCheck-newtype GTestString = GTestString String-newtype GTestString2 = GTestString2 String--fromGTestString :: GTestString -> String-fromGTestString (GTestString s) = s--fromGTestString2 :: GTestString2 -> String-fromGTestString2 (GTestString2 s) = s--instance Arbitrary GTestString where-  arbitrary =-    oneof $ map (return . GTestString) $-    [ "a", "apple" , "b", "banana", "c", "carrot", "d", "durian"-    , "e", "eggplant", "f", "fennel" , "g", "grape" ]-  coarbitrary = error "no implementation of coarbitrary for GTestString"--instance Arbitrary GTestString2 where-  arbitrary =-    oneof $ map (return . GTestString2) $-    [ "X", "Y", "Z", "H", "I", "J", "P", "Q", "R", "S", "T", "U"  ]-  coarbitrary = error "no implementation of coarbitrary for GTestString2"+{-# LANGUAGE OverlappingInstances, FlexibleInstances, TemplateHaskell #-}+{-# LANGUAGE DeriveDataTypeable #-}+module NLP.GenI.GeniVal+  ( -- * GeniVal+    GeniVal, gLabel, gConstraints+  , mkGConst, mkGConstNone, mkGVar, mkGVarNone, mkGAnon+    -- ** queries and manipulation+  , isVar, isAnon, isConst, singletonVal+  , crushOne+    -- * Unification and subsumption+    --+    -- ** Finalisation+    --+    -- Before you do any unification/subsumption, you should finalise all+    -- the variables in all the objects (a one time alpha-conversion type+    -- thing)+  , finaliseVars, finaliseVarsById+    -- ** Unification+  , unify, UnificationResult(..), Subst, appendSubst+    -- ** subsumption+  , subsumeOne, allSubsume -instance Arbitrary GeniVal where-  arbitrary = oneof [ return $ GAnon,-                      fmap (GVar . fromGTestString2) arbitrary,-                      fmap (GConst . nub . sort . map fromGTestString) arbitrary ]-  coarbitrary = error "no implementation of coarbitrary for GeniVal"+    -- * Traversing GeniVal containers+  , DescendGeniVal(..), Collectable(..), Idable(..)+  , replace, replaceList+  ) where -qc_not_empty_GConst :: GeniVal -> Bool-qc_not_empty_GConst (GConst []) = False-qc_not_empty_GConst _ = True+import NLP.GenI.GeniVal.Internal
+ src/NLP/GenI/GeniVal/Internal.hs view
@@ -0,0 +1,428 @@+-- GenI surface realiser+-- Copyright (C) 2009 Eric Kow+-- Copyright (C) 2005 Carlos Areces+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.++{-# LANGUAGE OverlappingInstances, FlexibleInstances, TemplateHaskell #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE OverloadedStrings #-}+module NLP.GenI.GeniVal.Internal where++-- import Debug.Trace -- for test stuff+import Control.Arrow (first, (***))+import Control.Monad (liftM)+import Data.Binary+import Data.List+import Data.Maybe (fromMaybe, isNothing, isJust)+import Data.Generics (Data)+import Data.Typeable (Typeable)+import qualified Data.Map as Map++import Data.Text ( Text )+import qualified Data.Text as T++import Control.DeepSeq++import Data.FullList ( FullList, fromFL, Listable(..), sortNub )+import NLP.GenI.General (geniBug, quoteText, isGeniIdentLetter)+import NLP.GenI.GeniShow+import NLP.GenI.Pretty++-- | constant : no label, just constraints+--   variable : label, with or without constraints+--   anonymous : no label, no constraints+data GeniVal = GeniVal { gLabel       :: Maybe Text+                       , gConstraints :: Maybe (FullList Text)+                       }+  deriving (Eq,Ord, Data, Typeable)++-- | 'mkGConst' @x :! []@ creates a single constant.  'mkGConst' @x :! xs@+--   creates an atomic disjunction.  It makes no difference which of the values+--   you supply for @x@ and @xs@ as they will be sorted and nubed anyway.+mkGConst :: FullList Text -- ^ non-empty list+         -> GeniVal+mkGConst cs_ = GeniVal Nothing (Just cs)+ where+  cs = sortNub cs_++mkGConstNone :: Text -> GeniVal+mkGConstNone x = mkGConst (x !: [])++mkGVar :: Text -> Maybe (FullList Text) -> GeniVal+mkGVar x mxs  = GeniVal (Just x) (sortNub `fmap` mxs)++mkGVarNone :: Text -> GeniVal+mkGVarNone x  = mkGVar x Nothing++mkGAnon :: GeniVal+mkGAnon       = GeniVal Nothing Nothing++{-+instance Show GeniVal where+  show = T.unpack . prettyGeniVal+-}++instance Pretty GeniVal where+    pretty = geniShowText++instance GeniShow GeniVal where+    geniShowText gv =+        case gv of+            GeniVal Nothing Nothing    -> showLabel "_"+            GeniVal Nothing (Just cs)  -> showConstraints cs+            GeniVal (Just l) Nothing   -> showLabel l+            GeniVal (Just l) (Just cs) ->+                showLabel l `T.append` "/" `T.append` showConstraints cs+      where+        showLabel l = '?' `T.cons` l+        showConstraints = T.intercalate "|" . map maybeQuote . fromFL -- FIXME push down+        maybeQuote x | T.null x        = quoteText ""+                     | "-" `T.isPrefixOf` x = quoteText x -- could be interpreted as+                     | "+" `T.isPrefixOf` x = quoteText x -- semantic polarities+                     | T.any naughty x = quoteText x+                     | otherwise       = x+        naughty x = not (isGeniIdentLetter x) || x `elem` "_?/"++isConst :: GeniVal -> Bool+isConst = isNothing . gLabel++singletonVal :: GeniVal -> Maybe Text+singletonVal v =+ case fmap fromFL (gConstraints v) of+    Just [o] -> Just o+    _        -> Nothing++isVar :: GeniVal -> Bool+isVar = isJust . gConstraints++isAnon :: GeniVal -> Bool+isAnon (GeniVal Nothing Nothing) = True+isAnon _     = False++-- ----------------------------------------------------------------------+-- Helper types+-- ----------------------------------------------------------------------++type Subst = Map.Map Text GeniVal++prettySubst :: Subst -> Text+prettySubst =+    T.unwords . map sho . Map.toList+  where+    sho (v,s) = v `T.append` "<-" `T.append` pretty s++-- ----------------------------------------------------------------------+-- Unification and subsumption+-- ----------------------------------------------------------------------++-- | 'unify' performs unification on two lists of 'GeniVal'.  If+--   unification succeeds, it returns @Just (r,s)@ where @r@ is+--   the result of unification and \verb!s! is a list of substitutions that+--   this unification results in.+unify :: Monad m => [GeniVal] -> [GeniVal] -> m ([GeniVal], Subst)+unify = unifyHelper unifyOne++-- | @l1 `allSubsume` l2@ returns the result of @l1 `unify` l2@ if+--   doing a simultaneous traversal of both lists, each item in+--   @l1@ subsumes the corresponding item in @l2@+allSubsume :: Monad m => [GeniVal] -> [GeniVal] -> m ([GeniVal], Subst)+allSubsume = unifyHelper subsumeOne++unifyHelper :: Monad m+            => (GeniVal -> GeniVal -> UnificationResult)+            -> [GeniVal]+            -> [GeniVal]+            -> m ([GeniVal], Subst)+unifyHelper f ll1 ll2 = repropagate `liftM` helper ll1 ll2+ where+  repropagate (xs, sub) = (replace sub xs, sub)+  helper [] l2 = return (l2, Map.empty)+  helper l1 [] = return (l1, Map.empty)+  helper (h1:t1) (h2:t2) =+    case f h1 h2 of+    Failure -> fail . T.unpack . T.unwords $+                   [ "unification failure between"+                   , pretty h1, "and"+                   , pretty h2+                   ]+    SuccessRep v g -> prepend `liftM` helper t1b t2b+                      where+                       s   = (v,g)+                       t1b = replaceOne s t1+                       t2b = replaceOne s t2+                       prepend = (g:) *** prependToSubst s+    SuccessRep2 v1 v2 g -> prepend `liftM` helper t1b t2b+                      where+                       s1  = (v1,g)+                       s2  = (v2,g)+                       t1b = replaceOne s2 . replaceOne s1 $ t1+                       t2b = replaceOne s2 . replaceOne s1 $ t2+                       prepend = (g:) *** (prependToSubst s1 . prependToSubst s2)+    SuccessSans g  -> first (g:) `liftM` helper t1 t2++-- | Note that the first Subst is assumed to come chronologically+--   before the second one; so merging @{ X -> Y }@ and @{ Y -> 3 }@+--   should give us @{ X -> 3; Y -> 3 }@;+--+--   See 'prependToSubst' for a warning!+appendSubst :: Subst -> Subst -> Subst+appendSubst sm1 sm2 = Map.foldrWithKey (curry prependToSubst) sm2 sm1++-- | Add to variable replacement to a 'Subst' that logical comes before+--   the other stuff in it.  So for example, if we have @Y -> foo@+--   and we want to insert @X -> Y@, we notice that, in fact, @Y@ has+--   already been replaced by @foo@, so we add @X -> foo@ instead+--+--   Note that it is undefined if you try to append something like+--   @Y -> foo@ to @Y -> bar@, because that would mean that unification+--   is broken+prependToSubst :: (Text,GeniVal) -> Subst -> Subst+prependToSubst (v, gr@(GeniVal (Just r) _)) sm =+  case Map.lookup v sm of+    Just v2 -> geniBug . unlines $+                [ "prependToSubst: GenI just tried to prepend the substitution"+                , "  " ++ prettyStr (mkGVar v Nothing) ++ " -> " ++ prettyStr gr+                , "to one where where "+                , "  " ++ prettyStr (mkGVar v Nothing) ++ " -> " ++ prettyStr v2+                , "is slated to occur afterwards."+                , ""+                , "This could mean that either"+                , " (a) the core unification algorithm is broken"+                , " (b) we failed to propagate a value somewhere or"+                , " (c) we are attempting unification without renaming."+                ]+    Nothing -> Map.insert v gr2 sm+  where gr2 = fromMaybe gr $ Map.lookup r sm+prependToSubst (v, gr) sm = Map.insert v gr sm++-- ----------------------------------------------------------------------+-- Core unification+-- TODO: would continuation passing style make this more efficient?+-- ----------------------------------------------------------------------++data UnificationResult = SuccessSans GeniVal+                       | SuccessRep  Text GeniVal+                       | SuccessRep2 Text Text GeniVal+                       | Failure++-- | See source code for details+--+--   Note that we assume that it's acceptable to generate new+--   variable names by appending an 'x' to them; this assumption+--   is only safe if the variables have gone through the function+--   'finaliseVarsById' or have been pre-processed and rewritten+--   with some kind of common suffix to avoid an accidental match+unifyOne :: GeniVal -> GeniVal -> UnificationResult+unifyOne (GeniVal Nothing Nothing) g = SuccessSans g+unifyOne g (GeniVal Nothing Nothing) = SuccessSans g+unifyOne g1 g2 =+    maybe Failure constrSuccess (intersectConstraints gc1 gc2)+  where+    gc1 = gConstraints g1+    gc2 = gConstraints g2+    constrSuccess cs =+        case (gLabel g1, gLabel g2) of+            (Nothing, Nothing) -> SuccessSans  (GeniVal Nothing cs)+            (Nothing, Just v)  -> SuccessRep v (GeniVal Nothing cs)+            (Just v, Nothing)  -> SuccessRep v (GeniVal Nothing cs)+            (Just v1, Just v2) -> bothLabeled cs v1 v2+    bothLabeled cs v1 v2+        | v1 == v2 && gc1 /= gc2 = geniBug constraintBug+        | v1 == v2               = SuccessSans g1+        | gc1 == gc2             = successSameConstraints cs v1 v2+        | otherwise              = successDiffConstraints cs v1 v2+    successSameConstraints cs v1 v2 =+        SuccessRep (min v1 v2) $ GeniVal (Just (max v1 v2)) cs+    successDiffConstraints cs v1 v2 =+        -- min/max stuff for symmetry+        SuccessRep2 (min v1 v2) (max v1 v2) $+        GeniVal (Just (max v1 v2 `T.append` "-g")) cs+    constraintBug = unwords+        [ "I just tried to unify variable with itself,"+        , "but it has mismatching constraints:"+        , prettyStr g1,  "vs."+        , prettyStr g2+        ]++intersectConstraints :: Eq a => Maybe (FullList a) -> Maybe (FullList a) -> Maybe (Maybe (FullList a))+intersectConstraints Nothing cs = Just cs+intersectConstraints cs Nothing = Just cs+intersectConstraints (Just v1) (Just v2) =+  case fromFL v1 `intersect` fromFL v2 of+    []     -> Nothing+    (x:xs) -> Just (Just (x !: xs))++-- ----------------------------------------------------------------------+-- Core subsumption+-- ----------------------------------------------------------------------++-- | 'subsumeOne' @x y@ returns the same result as @unifyOne x y@ if @x@+--   subsumes @y@ or 'Failure' otherwise+subsumeOne :: GeniVal -> GeniVal -> UnificationResult+subsumeOne g1@(GeniVal _ (Just cs1)) g2@ (GeniVal _ (Just cs2)) =+   if fromFL cs1 `subset` fromFL cs2 then unifyOne g1 g2 else Failure+ where+   subset x y = all (`elem` y) x+subsumeOne (GeniVal _ (Just _)) (GeniVal _ Nothing) = Failure+subsumeOne g1@(GeniVal _ Nothing) g2 = unifyOne g1 g2++-- ----------------------------------------------------------------------+-- Variable substitution+-- ----------------------------------------------------------------------++replace :: DescendGeniVal a => Subst -> a -> a+replace m | Map.null m = id+replace m = descendGeniVal (replaceMapG m)++replaceOne :: DescendGeniVal a => (Text, GeniVal) -> a -> a+replaceOne = descendGeniVal . replaceOneG++-- | Here it is safe to say (X -> Y; Y -> Z) because this would be crushed+--   down into a final value of (X -> Z; Y -> Z)+replaceList :: DescendGeniVal a => [(Text,GeniVal)] -> a -> a+replaceList = replace . foldl' update Map.empty+  where+   update m (s1,s2) = Map.insert s1 s2 $ Map.map (replaceOne (s1,s2)) m++replaceMapG :: Subst -> GeniVal -> GeniVal+replaceMapG m v@(GeniVal (Just v_) _) = Map.findWithDefault v v_ m+replaceMapG _ v = v++replaceOneG :: (Text, GeniVal) -> GeniVal -> GeniVal+replaceOneG (s1, s2) (GeniVal (Just v_) _) | v_ == s1 = s2+replaceOneG _ v = v++-- ----------------------------------------------------------------------+-- Variable collection and renaming+-- ----------------------------------------------------------------------++type CollectedVar = (Text, Maybe (FullList Text))++-- | A 'Collectable' is something which can return its variables as a+--   map from the variable to the number of times that variable occurs+--   in it.+--+--   Important invariant: if the variable does not occur, then it does+--   not appear in the map (ie. all counts must be >= 1 or the item+--   does not occur at all)+--+--   By variables, what I most had in mind was the GVar values in a+--   GeniVal.  This notion is probably not very useful outside the context of+--   alpha-conversion task, but it seems general enough that I'll keep it+--   around for a good bit, until either some use for it creeps up, or I find+--   a more general notion that I can transform this into.+class Collectable a where+  collect :: a -> Map.Map CollectedVar Int -> Map.Map CollectedVar Int++instance Collectable a => Collectable (Maybe a) where+  collect Nothing  s = s+  collect (Just x) s = collect x s++instance (Collectable a => Collectable [a]) where+  collect l s = foldr collect s l++instance Collectable GeniVal where+  collect (GeniVal (Just v) cs) s = Map.insertWith' (+) (v,cs) 1 s+  collect (GeniVal Nothing _)   s = s++-- | An Idable is something that can be mapped to a unique id.+--   You might consider using this to implement Ord, but I won't.+--   Note that the only use I have for this so far (20 dec 2005)+--  is in alpha-conversion.+class Idable a where+  idOf :: a -> Integer++-- | Anonymise any variable that occurs only once in the object+anonymiseSingletons :: (Collectable a, DescendGeniVal a) => a -> a+anonymiseSingletons x =+   replace subst x+ where+   subst = Map.map (const mkGAnon) . Map.filter (== 1)+           -- merge counts for same var, different constraints+         . Map.fromListWith (+) . map (first fst) . Map.toList+         $ collect x Map.empty++-- 'finaliseVarsById' appends a unique suffix to all variables in+-- an object.  This avoids us having to alpha convert all the time+-- and relies on the assumption finding that a unique suffix is+-- possible.+finaliseVarsById :: (Collectable a, DescendGeniVal a, Idable a) => a -> a+finaliseVarsById x = finaliseVars ('-' `T.cons` (T.pack . show $ idOf x)) x++-- | 'finaliseVars' does the following:+--+--   * (if suffix is non-null) appends a suffix to all variable names+--     to ensure global uniqueness+--+--   * anonymises any singleton variables+---+---   * intersects constraints for for all variables within the same+---     object+finaliseVars :: (Collectable a, DescendGeniVal a) => Text -> a -> a+finaliseVars suffix x = {-# SCC "finaliseVars" #-}+  replace subst (anonymiseSingletons x)+ where+   subst :: Subst+   subst = Map.mapWithKey convert vars+   vars  = Map.fromListWithKey isect $ Map.keys (collect x Map.empty)+   -- TODO: ugh: this is maybe not ideal: if a variable has impossible+   -- constraints (eg. ?X/cat cannot unify with ?X/dog, but it can+   -- unify with ?X/cat vs ?X/dog|cat => ?X/cat), we hardcode it to a+   -- value that should not be able to unify with anything+   isect k xi yi =+      fromMaybe (Just (impossibleC k)) $ intersectConstraints xi yi+   convert v = GeniVal (Just (v `T.append` suffix))+   impossibleC v =  ("ERROR_impossible_constraints_" `T.append` v `T.append` suffix)+                 !: []++-- ----------------------------------------------------------------------+-- Fancy disjunction+-- ----------------------------------------------------------------------++crushOne :: [GeniVal] -> Maybe GeniVal+crushOne []   = Nothing+crushOne [gs] = Just gs+crushOne gs   =+  if any isNothing gcs+     then Nothing+     else case concat [ fromFL c | Just c <- gcs ] of+            []     -> Nothing+            (c:cs) -> Just (mkGConst (c !: cs))+  where+   gcs = map gConstraints gs++crushList :: [[GeniVal]] -> Maybe [GeniVal]+crushList = mapM crushOne++-- ----------------------------------------------------------------------+-- Genericity+-- ----------------------------------------------------------------------++class DescendGeniVal a where+  descendGeniVal :: (GeniVal -> GeniVal) -> a -> a++instance DescendGeniVal GeniVal where+  descendGeniVal f = f++instance (Functor f, DescendGeniVal a) => DescendGeniVal (f a) where+  descendGeniVal = fmap . descendGeniVal++instance NFData GeniVal where+  rnf (GeniVal x y) = rnf x `seq` rnf y++instance Binary GeniVal where+  put (GeniVal a b) = put a >> put b+  get = get >>= \a -> get >>= \b -> return (GeniVal a b)
− src/NLP/GenI/Graphviz.hs
@@ -1,214 +0,0 @@-{-# OPTIONS -fglasgow-exts #-}--{-- GenI surface realiser- Copyright (C) 2005 Carlos Areces and Eric Kow- - This program is free software; you can redistribute it and/or- modify it under the terms of the GNU General Public License- as published by the Free Software Foundation; either version 2- of the License, or (at your option) any later version.- - This program is distributed in the hope that it will be useful,- but WITHOUT ANY WARRANTY; without even the implied warranty of- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the- GNU General Public License for more details.- - You should have received a copy of the GNU General Public License- along with this program; if not, write to the Free Software- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.--}--{- | Graphviz is an open source tool which converts an abstract-     representation of a graph (node foo is connected to node bar, etc.)-     into a nicely laid out graphic.  This module contains methods -     to invoke graphviz and to convert graphs and trees to its input format.--     You can download this (open source) tool at-     <http://www.research.att.com/sw/tools/graphviz>--}--module NLP.GenI.Graphviz-where--import Control.Monad(when)-import Data.List(intersperse)-import Data.Tree-import System.IO ( hClose )-import System.IO.UTF8-import Prelude hiding ( writeFile )-import System.Exit(ExitCode)--import NLP.GenI.SysGeni(waitForProcess, runInteractiveProcess)--{- |-     Data structures which can be visualised with GraphViz should-     implement this class.  Note the first argument to graphvizShowGraph is-     so that you can parameterise your show function (i.e. pass in-     flags to change the way you show particular object).  Note-     that by default, all graphs are treated as directed graphs.  You-     can hide this by turning off edge arrows.--}-class GraphvizShow flag b where-  graphvizShowGraph       :: flag -> b -> String-  graphvizShowAsSubgraph  :: flag   -- ^ flag-                          -> String -- ^ prefix-                          -> b      -- ^ item-                          -> String -- ^ gv output -  graphvizLabel           :: flag   -- ^ flag-                          -> b      -- ^ item-                          -> String -- ^ gv output-  graphvizParams          :: flag -> b -> [String] --  graphvizShowGraph f b  = -    let l = graphvizLabel f b-    in "digraph {\n" -       ++ (unlines $ graphvizParams f b)-       ++ graphvizShowAsSubgraph f "_" b ++ "\n"-       ++ (if null l then "" else " label = \"" ++ l ++ "\";\n")-       ++ "}"-  graphvizLabel _ _ = ""-  graphvizParams _ _ = []--class GraphvizShowNode flag b where-  graphvizShowNode :: flag   -- ^ flag -                   -> String -- ^ prefix -                   -> b      -- ^ item -                   -> String -- ^ gv output---- | Things which are meant to be displayed within some other graph---   as (part) of a node label-class GraphvizShowString flag b where-  graphvizShow :: flag   -- ^ flag-               -> b      -- ^ item-               -> String -- ^ gv output---- | Note: the 'dotFile' argument allows you to save the intermediary--- dot output to a file.  You can pass in the empty string if you don't-toGraphviz :: (GraphvizShow f a) => f -                                 -> a -                                 -> String -- ^ the 'dotFile'-                                 -> String -> IO ExitCode -toGraphviz p x dotFile outputFile = do-   graphviz (graphvizShowGraph p x) dotFile outputFile---- ------------------------------------------------------------------------ useful utility functions--- -----------------------------------------------------------------------gvNewline :: String-gvNewline  = "\\n"--gvUnlines :: [String] -> String-gvUnlines = concat . (intersperse gvNewline)--gvSubgraph :: String -> String-gvSubgraph g = "subgraph {\n" ++ g ++ "}\n"---- | The Graphviz string for a node.  Note that we make absolutely no--- effort to escape any characters for you; so if you need to protect--- anything from graphviz, you're on your own-gvNode :: String                 -- ^ the node name-            -> String            -- ^ the label (may be empty)-            -> [(String,String)] -- ^ any other parameters-            -> String-gvNode name label params =  -  " " ++ name ++ " " ++ (gvLabelAndParams label params) ++ "\n"---- | The Graphviz string for a connection between two nodes.  --- Same disclaimer as 'gvNode' applies.-gvEdge :: String  -- ^ the 'from' node-            -> String  -- ^ the 'to' node-            -> String  -- ^ the label (may be empty)-            -> [(String,String)] -- ^ any other parameters -            -> String-gvEdge from to label params = -  " " ++ from ++ " -> " ++ to ++ (gvLabelAndParams label params) ++ "\n"--gvLabelAndParams :: String -> [(String,String)] -> String-gvLabelAndParams l p = -  gvParams $ if null l then p else ("label", l) : p--gvParams :: [(String,String)] -> String-gvParams [] = ""-gvParams p  = "[ " ++ (concat $ intersperse ", " $ map showPair p) ++ " ]"-  where showPair (a,v) = a ++ "=\"" ++ v ++ "\""---- ------------------------------------------------------------------------ some instances --- -----------------------------------------------------------------------instance (GraphvizShow f b) => GraphvizShow f (Maybe b) where-  graphvizShowAsSubgraph _ _ Nothing  = ""-  graphvizShowAsSubgraph f p (Just b) = graphvizShowAsSubgraph f p b --  graphvizLabel _ Nothing  = ""-  graphvizLabel f (Just b) = graphvizLabel f b--  graphvizParams _ Nothing = [] -  graphvizParams f (Just b) = graphvizParams f b---- | Displays a tree in graphviz format.  -{- Note that we could make this an-   instance of GraphvizShow, but I'm not too sure about the wisdom of-   such a move.  --   Maybe if we had some really super-sophisticated types in Haskell, where-   we can define this as the default instance which could be overrided by-   something more specific, that would be cool.--   The prefix argument is interpreted as the name of the top node.  Node-   names below are basically Gorn addresses (e.g. n0x2x3 means 3rd child of-   the 2nd child of the root) to keep them distinct.  Note : We use the-   letter `x' as seperator because graphviz will choke on `.' or `-', even-   underscore. -}-gvShowTree :: (GraphvizShowNode f n) => -     (n->[(String,String)]) -- ^ function to convert a node to a list of graphviz parameters for the edge -  -> f                      -- ^ GraphvizShow flag-  -> String                 -- ^ node prefix-  -> (Tree n)               -- ^ the tree-  -> String-gvShowTree edgeFn f prefix t = -  "edge [ arrowhead = none ]\n" ++ gvShowTreeHelper edgeFn f prefix t  --gvShowTreeHelper :: forall n . forall f . (GraphvizShowNode f n) => (n->[(String,String)]) -> f -> String -> (Tree n) -> String-gvShowTreeHelper edgeFn f prefix (Node node l) = -   let showNode = graphvizShowNode f prefix -       showKid :: Integer -> Tree n -> String-       showKid index kid = -         gvShowTreeHelper edgeFn f kidname kid ++ " " -         ++ (gvEdge prefix kidname "" (edgeFn node))-         where kidname = prefix ++ "x" ++ (show index)-   in showNode node ++ "\n" ++ (concat $ zipWith showKid [0..] l)---- ------------------------------------------------------------------------ invocation --- ------------------------------------------------------------------------- | Calls graphviz. If the second argument is the empty string, then we--- just send stuff directly to dot's stdin--graphviz :: String -- ^ graphviz's dot format.-         -> String -- ^ the name of the file graphviz should write the dot -         -> String -- ^ the name of the file graphviz should write its output -         -> IO ExitCode---- We write the dot String to a temporary file which we then feed to graphviz.--- This is avoid complications with fork and pipes.  We use png output even--- though it's uglier, because we don't have a wxhaskell widget that can --- display postscript... do we?--graphviz dot dotFile outputFile = do-   let dotArgs' = ["-Gfontname=courier", -                   "-Nfontname=courier", -                   "-Efontname=courier", -                   "-Gcharset=utf-8",-                   "-Tpng", "-o" ++ outputFile ]-       dotArgs = dotArgs' ++ (if (null dotFile) then [] else [dotFile])-   -- putStrLn ("sending to graphviz:\n" ++ dot) -   when (not $ null dotFile) $ writeFile dotFile dot-   (_, toGV, _, pid) <- runInteractiveProcess "dot" dotArgs Nothing Nothing-   when (null dotFile) $ do -     hPutStrLn toGV dot -     hClose toGV-   waitForProcess pid
− src/NLP/GenI/GraphvizShow.hs
@@ -1,199 +0,0 @@---  GenI surface realiser---  Copyright (C) 2009 Eric Kow------  This program is free software; you can redistribute it and/or---  modify it under the terms of the GNU General Public License---  as published by the Free Software Foundation; either version 2---  of the License, or (at your option) any later version.------  This program is distributed in the hope that it will be useful,---  but WITHOUT ANY WARRANTY; without even the implied warranty of---  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the---  GNU General Public License for more details.------  You should have received a copy of the GNU General Public License---  along with this program; if not, write to the Free Software---  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.--{-# LANGUAGE FlexibleInstances, TypeSynonymInstances, FlexibleContexts #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}--- | Outputting core GenI data to graphviz.-module NLP.GenI.GraphvizShow-where--import Data.List(intersperse,nub)-import Data.List.Split (wordsBy)-import Data.Maybe(listToMaybe)--import NLP.GenI.Tags- ( TagElem, TagDerivation, idname,-   tsemantics, ttree,-   DerivationStep(..),- )-import NLP.GenI.Btypes (GeniVal(GConst), AvPair(..),-               GNode(..), GType(..), Flist,-               isConst,-               showSem,-               )-import NLP.GenI.Graphviz-  ( gvUnlines, gvNewline-  , GraphvizShow(graphvizShowAsSubgraph, graphvizLabel, graphvizParams)-  , GraphvizShowNode(graphvizShowNode)-  , GraphvizShowString(graphvizShow)-  , gvNode, gvEdge, gvShowTree-  )---- ------------------------------------------------------------------------- For GraphViz--- ------------------------------------------------------------------------type GvHighlighter a = a -> (a, Maybe String)--nullHighlighter :: GvHighlighter GNode-nullHighlighter a = (a,Nothing)--instance GraphvizShow Bool TagElem where- graphvizShowAsSubgraph sf = graphvizShowAsSubgraph (sf, nullHighlighter)- graphvizLabel  sf = graphvizLabel (sf, nullHighlighter )- graphvizParams sf = graphvizParams (sf, nullHighlighter)---instance GraphvizShow (Bool, GvHighlighter GNode) TagElem where- graphvizShowAsSubgraph (sf,hfn) prefix te =-    (gvShowTree (\_->[]) sf (prefix ++ "DerivedTree0") $-     fmap hfn $ ttree te)-- graphvizLabel _ te =-  -- we display the tree semantics as the graph label-  let treename   = "name: " ++ (idname te)-      semlist    = "semantics: " ++ (showSem $ tsemantics te)-  in gvUnlines [ treename, semlist ]-- graphvizParams _ _ =-  [ "fontsize = 10", "ranksep = 0.3"-  , "node [fontsize=10]"-  , "edge [fontsize=10 arrowhead=none]" ]---- ------------------------------------------------------------------------- Helper functions for the TagElem GraphvizShow instance--- ------------------------------------------------------------------------instance GraphvizShowNode (Bool) (GNode, Maybe String) where- -- compact -> (node, mcolour) -> String- graphvizShowNode detailed prefix (gn, mcolour) =-   let -- attributes-       filledParam         = ("style", "filled")-       fillcolorParam      = ("fillcolor", "lemonchiffon")-       shapeRecordParam    = ("shape", "record")-       shapePlaintextParam = ("shape", "plaintext")-       ---       colorParams = case mcolour of-                     Nothing -> []-                     Just c  -> [ ("fontcolor", c) ]-       shapeParams = if detailed-                     then [ shapeRecordParam, filledParam, fillcolorParam ]-                     else [ shapePlaintextParam ]-       -- content-       stub  = showGnStub gn-       extra = showGnDecorations gn-       summary = if null extra then stub-                 else "{" ++ stub ++ "|" ++ extra ++ "}"-       ---       body = if not detailed then graphvizShow_ gn-              else    "{" ++ summary-                   ++ (barAnd.showFs $ gup gn)-                   ++ (maybeShow (barAnd.showFs) $ gdown gn)-                   ++ "}"-        where barAnd x = "|" ++ x-              showFs = gvUnlines . (map graphvizShow_)-   in gvNode prefix body (shapeParams ++ colorParams)--instance GraphvizShowString () GNode where-  graphvizShow () gn =-    let stub  = showGnStub gn-        extra = showGnDecorations gn-    in stub ++ extra--instance GraphvizShowString () AvPair where-  graphvizShow () (AvPair a v) = a ++ ":" ++ graphvizShow_ v--instance GraphvizShowString () GeniVal where-  graphvizShow () (GConst x) = concat $ intersperse " ! " x-  graphvizShow () x = show x--showGnDecorations :: GNode -> String-showGnDecorations gn =-  case gtype gn of-  Subs -> "↓"-  Foot -> "*"-  _    -> if gaconstr gn then "ᴺᴬ"   else ""--showGnStub :: GNode -> String-showGnStub gn =- let cat = case getGnVal gup "cat" gn of-           Nothing -> ""-           Just v  -> graphvizShow_ v-     ---     getIdx f =-       case getGnVal f "idx" gn of-       Nothing -> ""-       Just v  -> if isConst v then graphvizShow_ v else ""-     idxT = getIdx gup-     idxB = getIdx gdown-     idx  = idxT ++ (maybeShow_ "." idxB)-     ---     lexeme  = concat $ intersperse "!" $ glexeme gn- in concat $ intersperse ":" $ filter (not.null) [ cat, idx, lexeme ]--getGnVal :: (GNode -> Flist) -> String -> GNode -> Maybe GeniVal-getGnVal getFeat attr gn =-  listToMaybe [ v | AvPair a v <- getFeat gn, a == attr ]---- | Apply fn to s if s is not null-maybeShow :: ([a] -> String) -> [a] -> String-maybeShow fn s = if null s then "" else fn s--- | Prefix a string if it is not null-maybeShow_ :: String -> String -> String-maybeShow_ prefix s = maybeShow (prefix++) s--graphvizShow_ :: (GraphvizShowString () a) => a -> String-graphvizShow_ = graphvizShow ()---- ------------------------------------------------------------------------- Derivation tree--- ------------------------------------------------------------------------graphvizShowDerivation :: TagDerivation -> String-graphvizShowDerivation deriv =-  if (null histNodes)-     then ""-     else " node [ shape = plaintext ];\n"-          ++ (concatMap showHistNode histNodes)-          ++ (concatMap graphvizShowDerivation' deriv)-  where showHistNode n  = gvNode (gvDerivationLab n) (label n) []-        label n = case wordsBy (== ':') n of-                  name:fam:tree:_ -> name ++ ":" ++ fam ++ gvNewline ++ tree-                  _               -> n ++ " (geni/gv ERROR)"-        histNodes = reverse $ nub $ concatMap (\ (DerivationStep _ c p _) -> [c,p]) deriv--graphvizShowDerivation' :: DerivationStep -> String-graphvizShowDerivation' (DerivationStep substadj child parent _) =-  gvEdge (gvDerivationLab parent) (gvDerivationLab child) "" p-  where p = if substadj == 'a' then [("style","dashed")] else []---gvDerivationLab :: String -> String-gvDerivationLab xs = "Derivation" ++ gvMunge xs--newlineToSlashN :: Char -> String-newlineToSlashN '\n' = gvNewline-newlineToSlashN x = [x]---- | Node names can't have hyphens in them and newlines within the node---   labels should be represented literally as @\\n@.-gvMunge :: String -> String-gvMunge = map dot2x . filter (/= ':') . filter (/= '-')--dot2x :: Char -> Char-dot2x '.' = 'x'-dot2x c   = c
− src/NLP/GenI/GraphvizShowPolarity.lhs
@@ -1,130 +0,0 @@-% GenI surface realiser-% Copyright (C) 2005 Carlos Areces and Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.--\begin{code}-{-# LANGUAGE TypeSynonymInstances #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}-module NLP.GenI.GraphvizShowPolarity-where--import Data.List (intersperse)-import qualified Data.Map as Map--import NLP.GenI.Btypes(showSem)-import NLP.GenI.General(showInterval, isEmptyIntersect)-import NLP.GenI.Polarity(PolAut, PolState(PolSt), NFA(states, transitions), finalSt)-import NLP.GenI.Graphviz(GraphvizShow(..), gvUnlines, gvNewline, gvNode, gvEdge)-import NLP.GenI.Tags(idname)-\end{code}--\begin{code}-instance GraphvizShow () PolAut where-  -- we want a directed graph (arrows)-  graphvizShowGraph f aut =-     "digraph aut {\n"-     ++ "rankdir=LR\n"-     ++ "ranksep = 0.02\n"-     ++ "pack=1\n"-     ++ "edge [ fontsize=10 ]\n"-     ++ "node [ fontsize=10 ]\n"-     ++ graphvizShowAsSubgraph f "aut" aut-     ++ "}"--  ---  graphvizShowAsSubgraph _ prefix aut =-   let st  = (concat.states) aut-       ids = map (\x -> prefix ++ show x) ([0..] :: [Int])-       -- map which permits us to assign an id to a state-       stmap = Map.fromList $ zip st ids-   in ---      gvShowFinal aut stmap-      -- any other state should be an ellipse-      ++ "node [ shape = ellipse, peripheries = 1 ]\n"-      -- draw the states and transitions-      ++ (concat $ zipWith gvShowState ids st)-      ++ (concat $ zipWith (gvShowTrans aut stmap) ids st )-\end{code}--\begin{code}-gvShowState :: String -> PolState -> String-gvShowState stId st =-  -- note that we pass the label param explicitly to allow for null label-  gvNode stId "" [ ("label", showSt st) ]-  where showSt (PolSt pr ex po) = showPr pr ++ showEx ex ++ showPo po-        showPr _ = "" -- (_,pr,_) = pr ++ gvNewline-        showPo po = concat $ intersperse "," $ map showInterval po-        showEx ex = if null ex then "" else showSem ex ++ gvNewline-\end{code}--Specify that the final states are drawn with a double circle--\begin{code}-gvShowFinal :: PolAut -> Map.Map PolState String -> String-gvShowFinal aut stmap =-  if isEmptyIntersect (concat $ states aut) fin-  then ""-  else "node [ peripheries = 2 ]; "-  ++ concatMap (\x -> " " ++ lookupId x) fin-  ++ "\n"-  where fin = finalSt aut-        lookupId x = Map.findWithDefault "error_final" x stmap-\end{code}--Each transition is displayed with the name of the tree.  If there is more-than one transition to the same state, they are displayed on a single-label.--\begin{code}-gvShowTrans :: PolAut -> Map.Map PolState String-               -> String -> PolState -> String-gvShowTrans aut stmap idFrom st =-  let -- outgoing transition labels from st-      trans = Map.findWithDefault Map.empty st $ transitions aut-      -- returns the graphviz dot command to draw a labeled transition-      drawTrans (stTo,x) = case Map.lookup stTo stmap of-                             Nothing   -> drawTrans' ("id_error_" ++ (sem_ stTo)) x-                             Just idTo -> drawTrans' idTo x-                           where sem_ (PolSt i _ _) = show i-                                 --showSem (PolSt (_,pred,_) _ _) = pred-      drawTrans' idTo x = gvEdge idFrom idTo (drawLabel x) []-      drawLabel labels  = gvUnlines labs-        where-          lablen  = length labels-          maxlabs = 6-          excess = "...and " ++ (show $ lablen - maxlabs) ++ " more"-          ---          labstrs = map fn labels-          fn Nothing  = "EMPTY"-          fn (Just x) = idname x-          ---          labs = if lablen > maxlabs-                 then take maxlabs labstrs ++ [ excess ]-                 else labstrs-  in unlines $ map drawTrans $ Map.toList trans-\end{code}--%gvShowTransPred te =-%  let p = tpredictors te-%      charge fv = case () of _ | c == -1   -> "-"-%                               | c ==  1   -> "+"-%                               | c  >  0   -> "+" ++ (show c)-%                               | otherwise -> (show c)-%                  where c = lookupWithDefaultFM p 0 fv-%      showfv (f,v) = charge (f,v) ++ f-%                   ++ (if (null v) then "" else ":" ++ v)-%  in map showfv $ Map.keys p-
− src/NLP/GenI/Gui.lhs
@@ -1,778 +0,0 @@-% GenI surface realiser-% Copyright (C) 2005 Carlos Areces and Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.--\chapter{Graphical User Interface} --\begin{code}-{-# LANGUAGE FlexibleContexts #-}-module NLP.GenI.Gui(guiGeni) where-\end{code}--\ignore{-\begin{code}-import Graphics.UI.WX--import qualified Control.Monad as Monad -import qualified Data.Map as Map--import Data.IORef-import Data.List (isPrefixOf, nub, delete, findIndex)-import Data.Maybe ( fromMaybe )-import System.Directory -import System.Exit (exitWith, ExitCode(ExitSuccess))--import qualified NLP.GenI.Builder as B-import qualified NLP.GenI.BuilderGui as BG-import NLP.GenI.Geni-  ( ProgState(..), ProgStateRef, combine, initGeni-  , lemmaSentenceString, GeniResult(..), prettyResult-  , loadEverything, loadTestSuite, loadTargetSemStr-  , showRealisations )-import NLP.GenI.General (boundsCheck, geniBug, trim, fst3)-import NLP.GenI.Btypes (TestCase(..), showFlist,)-import NLP.GenI.Tags (idname, tpolarities, TagElem)-import NLP.GenI.GeniShow (geniShow)-import NLP.GenI.Configuration-  ( Params(..), Instruction, hasOpt-  , hasFlagP, deleteFlagP, setFlagP, getFlagP, getListFlagP-  , parseFlagWithParsec-    ---  , ExtraPolaritiesFlg(..)-  , LexiconFlg(..)-  , MacrosFlg(..)-  , MorphCmdFlg(..)-  , MorphInfoFlg(..)-  , OptimisationsFlg(..)-  , RankingConstraintsFlg(..)-  , RootFeatureFlg(..)-  , TestSuiteFlg(..)-  , TestInstructionsFlg(..)-  , ViewCmdFlg(..)-  ---  , Optimisation(..)-  , BuilderType(..), mainBuilderTypes )-import NLP.GenI.GeniParsers hiding ( choice, label, tab )-import NLP.GenI.GuiHelper--import NLP.GenI.Polarity-import NLP.GenI.Simple.SimpleGui-import NLP.GenI.Statistics (Statistics, showFinalStats)-\end{code}-}--\section{Main Gui}--\begin{code}-guiGeni :: ProgStateRef -> IO() -guiGeni pstRef = start $ mainGui pstRef-\end{code}--When you first start GenI, you will see this screen:--\begin{center}-\includegraphics[width=0.47\textwidth]{hcar/GenI-main-screenshot.jpg}-\end{center}--It allows you to type in an input semantics (or to modify the one that was-automatically loaded up), select some optimisations and run the realiser.  You-can also opt to run the debugger instead of the realiser (section-\ref{sec:gui:debugger}).--\begin{code}-mainGui :: ProgStateRef -> IO ()-mainGui pstRef -  = do ---       pst <- readIORef pstRef-       -- Top Window-       f <- frame [text := "Geni Project"]-       -- create statusbar field-       status <- statusField   []-       -- create the file menu-       fileMen   <- menuPane [text := "&File"]-       loadMenIt <- menuItem fileMen [text := "&Open files or configure GenI"]-       quitMenIt <- menuQuit fileMen [text := "&Quit"]-       set quitMenIt [on command := close f ]-       -- create the tools menu-       toolsMen      <- menuPane [text := "&Tools"]-       gbrowserMenIt <- menuItem toolsMen [ text := "&Inspect grammar" -                                          , help := "Displays the trees in the grammar" ]-       -- create the help menu-       helpMen   <- menuPane [text := "&Help"]-       aboutMeIt <- menuAbout helpMen [help := "About"]-       -- Tie the menu to this window-       set f [ statusBar := [status] -             , menuBar := [fileMen, toolsMen, helpMen]-             -- put the menu event handler for an about box on the frame.-             , on (menu aboutMeIt) := infoDialog f "About GenI" "The GenI generator.\nhttp://wiki.loria.fr/wiki/GenI" -             -- event handler for the tree browser-             , on (menu gbrowserMenIt) := do { loadEverything pstRef; treeBrowserGui pstRef }  -             ]-       -- ------------------------------------------------------------------       -- buttons-       -- ------------------------------------------------------------------       let config     = pa pst -           hasSem     = hasFlagP TestSuiteFlg config-       -- Target Semantics-       testSuiteChoice <- choice f [ selection := 0, enabled := hasSem ]-       tsTextBox <- textCtrl f [ wrap := WrapWord-                               , clientSize := sz 400 80-                               , enabled := hasSem -                               , text := "" ]-       testCaseChoice <- choice f [ selection := 0 -                                  , enabled := hasSem ]-       -- Box and Frame for files loaded -       macrosFileLabel  <- staticText f [ text := getListFlagP MacrosFlg config  ]-       lexiconFileLabel <- staticText f [ text := getListFlagP LexiconFlg config ]-       -- Generate and Debug -       let genfn = doGenerate f pstRef tsTextBox-       pauseOnLexChk <- checkBox f [ text := "Inspect lex", tooltip := "Affects debugger only"  ]-       debugBt <- button f [ text := "Debug"-                           , on command := get pauseOnLexChk checked >>= genfn True ]-       genBt  <- button f  [text := "Generate", on command := genfn False False ]-       quitBt <- button f  [ text := "Quit",-                 on command := close f]-       -- ------------------------------------------------------------------       -- optimisations-       -- ------------------------------------------------------------------       algoChoiceBox <- radioBox f Vertical (map show mainBuilderTypes)-                        [ selection := case builderType config of-                                       SimpleBuilder -> 0-                                       SimpleOnePhaseBuilder -> 1-                                       NullBuilder   -> 0 ]-       set algoChoiceBox [ on select := toggleAlgo pstRef algoChoiceBox ]-       polChk <- optCheckBox Polarised pstRef f-          [ text := "Polarities"-          , tooltip := "Use the polarity optimisation"-          ]-       useSemConstraintsChk <- antiOptCheckBox NoConstraints pstRef f-         [ text := "Sem constraints"-         , tooltip := "Use any sem constraints the user provides"-         ]-       earlyNaChk <- optCheckBox EarlyNa pstRef f-          [ text := "NA detection"-          , tooltip := "Early detection of nodes that cannot be adjoined to"-          ]-       iafChk <- optCheckBox Iaf pstRef f-          [ text := "Idx acc filter"-          , tooltip := "Only available in CKY/Earley for now"-          ]-       semfilterChk <- optCheckBox SemFiltered pstRef f-         [ text := "Semantic filters"-         , tooltip := "(2p only) Filter away semantically incomplete structures before adjunction phase"-         ]-       extrapolText <- staticText f -         [ text := maybe "" showLitePm $ getFlagP ExtraPolaritiesFlg config-         , tooltip := "Use the following additional polarities" -         ]-       -- commands for the checkboxes-       let togglePolStuff = do c <- get polChk checked-                               set extrapolText [ enabled := c ]-       set polChk [on command :~ (>> togglePolStuff) ]-       -- ------------------------------------------------------------------       -- layout; packing it all together-       -- ------------------------------------------------------------------       -- set any last minute handlers, run any last minute functions-       let onLoad = readConfig f pstRef macrosFileLabel lexiconFileLabel testSuiteChoice tsTextBox testCaseChoice-       set loadMenIt [ on command := do configGui pstRef onLoad ]-       onLoad-       togglePolStuff-       ---       let labeledRow l w = row 1 [ label l, hfill (widget w) ]-       let gramsemBox = boxed "Files last loaded" $ -                   hfill $ column 1 -                     [ labeledRow "trees:"   macrosFileLabel-                     , labeledRow "lexicon:" lexiconFileLabel-                     ]-           optimBox =  --boxed "Optimisations " $ -- can't used boxed with wxwidgets 2.6 -- bug?-                    column 5 [ label "Algorithm"-                             , dynamic $ widget algoChoiceBox-                             , label "Optimisations"-                             , dynamic $ widget polChk -                             , row 5 [ label "  ", column 5 -                                     [ dynamic $ row 5 [ label "Extra: ", widget extrapolText ] ] ]-                             , dynamic $ widget useSemConstraintsChk-                             , dynamic $ widget semfilterChk -                             , dynamic $ widget earlyNaChk-                             , dynamic $ widget iafChk-                             ]-       set f [layout := column 5 [ gramsemBox-                   , row 5 [ fill $ -- boxed "Input Semantics" $ -                             hfill $ column 5 -                               [ labeledRow "test suite: " testSuiteChoice-                               , labeledRow "test case: "  testCaseChoice-                               , fill  $ widget tsTextBox ]-                           , vfill optimBox ]-                    -- ----------------------------- Generate and quit -                   , row 1 [ widget quitBt -                          , hfloatRight $ row 5 [ widget pauseOnLexChk, widget debugBt, widget genBt ]] ]-            , clientSize := sz 525 325-            , on closing := exitWith ExitSuccess -            ]---- Note the following point about anti-optimisations: An anti-optimisation--- disables a default behaviour which is assumed to be "optimisation".  But of--- course we don't want to confuse the GUI user, so we confuse the programmer--- instead: Given an anti-optimisation DisableFoo, we have a check box UseFoo.  If--- UseFoo is checked, we remove DisableFoo from the list; if it is unchecked, we--- add it to the list.  This is the opposite of the default behaviour, but the--- result, I hope, is intuitive for the user.-toggleAlgo :: (Selection a, Items a String) => ProgStateRef -> a -> IO ()-toggleAlgo pstRef box =- do asel   <- get box selection-    aitems <- get box items-    let selected = aitems !! asel-        btable = zip (map show mainBuilderTypes) mainBuilderTypes-        btype = case [ b | (name, b) <- btable, name == selected ] of-                []  -> geniBug $ "Unknown builder type " ++ selected-                [b] -> b-                _   -> geniBug $ "More than one builder has the name " ++ selected-    modifyIORef pstRef (\x -> x { pa = (pa x) { builderType = btype } })--optCheckBox, antiOptCheckBox ::-  Optimisation -> ProgStateRef-               -> Window a -> [Prop (CheckBox ())]-               -> IO (CheckBox ())---- | Checkbox for enabling or disabling an optimisation---   You need not set the checked or on command attributes---   as this is done for you (but you can if you want,---   setting checked will override the default, and any---   command you set will be run before the toggle stuff)-optCheckBox = optCheckBoxHelper id---- | Same as 'optCheckBox' but for anti-optimisations-antiOptCheckBox = optCheckBoxHelper not--optCheckBoxHelper :: (Bool -> Bool) -> Optimisation -> ProgStateRef-                  -> Window a -> [Prop (CheckBox ())]-                  -> IO (CheckBox ())-optCheckBoxHelper idOrNot o pstRef f as =-  do pst <- readIORef pstRef-     chk <- checkBox f $ [ checked := idOrNot $ hasOpt o $ pa pst ] ++ as-     set chk [ on command :~ (>> onCheck chk) ]-     return chk-  where-   onCheck chk =-    do isChecked <- get chk checked-       pst <- readIORef pstRef-       let config  = pa pst-           modopt  = if idOrNot isChecked then (o:) else delete o-           newopts = nub.modopt $ getListFlagP OptimisationsFlg config-       modifyIORef pstRef (\x -> x{pa = setFlagP OptimisationsFlg newopts (pa x)})---- ----------------------------------------------------------------------- Loading files--- ------------------------------------------------------------------------ | 'readConfig' is used to update the graphical interface after---    you run the  'configGui'.---    It is also called when you first launch the GUI-readConfig :: (Textual l, Textual t, Able ch, Items ch String, Selection ch, Selecting ch)-           => Window w -> ProgStateRef -> l -> l -> ch -> t -> ch -> IO ()-readConfig f pstRef macrosFileLabel lexiconFileLabel suiteChoice tsBox caseChoice =-  do pst <- readIORef pstRef-     let config = pa pst-         -- errHandler title err = errorDialog f title (show err)-     set macrosFileLabel  [ text := getListFlagP MacrosFlg config ]-     set lexiconFileLabel [ text := getListFlagP LexiconFlg config ]-     -- set tsFileLabel      [ text := getListFlagP TestSuiteFlg config ]-     -- read the test suite if there is one-     case getListFlagP TestInstructionsFlg config of-       [] ->-         do set suiteChoice [ enabled := False, items := [] ]-            set caseChoice  [ enabled := False, items := [] ]-       is ->-         do -- handler for selecting a test suite-            let imap = Map.fromList $ zip [0..] is-                onTestSuiteChoice = do-                  sel <- get suiteChoice selection-                  case Map.lookup sel imap of-                    Nothing -> geniBug $ "No such index in test suite selector (gui): " ++ show sel-                    Just t  -> loadTestSuiteAndRefresh f pstRef t tsBox caseChoice-            set suiteChoice [ enabled := True, items := map fst is-                            , on select := onTestSuiteChoice, selection := 0 ]-            set caseChoice  [ enabled := True ]-            onTestSuiteChoice -- load the first suite---- | Load the given test suite and update the GUI accordingly.---   This is used when you first start the graphical interface---   or when you run the configuration menu.-loadTestSuiteAndRefresh :: (Textual a, Selecting b, Selection b, Items b String) -              => Window w -> ProgStateRef -> Instruction -> a -> b -> IO ()-loadTestSuiteAndRefresh f pstRef (suitePath,mcs) tsBox caseChoice =-  do (loadTestSuite pstRef >> return ())-       `catch` \e -> errorDialog f ("Error reading test suite " ++ suitePath) (show e)-     pst <- readIORef pstRef-     let suite   = tsuite pst-         theCase = tcase pst-         suiteCases = case filter (\c -> tcName c `elem` cs) suite of-                       []  -> suite-                       res -> res-           where cs = fromMaybe [] mcs-         suiteCaseNames = map tcName suiteCases-     -- we number the cases for easy identification, putting -     -- a star to highlight the selected test case (if available)-     let numfn :: Int -> String -> String-         numfn n t = (if t == theCase then "* " else "")-                      ++ (show n) ++ ". " ++ t-         tcaseLabels = zipWith numfn [1..] suiteCaseNames-     -- we select the first case in cases_, if available-     caseSel <- if null theCase-                   then return 0-                   else case findIndex (== theCase) suiteCaseNames of-                               Nothing -> do errorDialog f "" ("No such test case: " ++ theCase)-                                             return 0-                               Just i  -> return i-     -----------------------------------------------------     -- handler for selecting a test case-     -----------------------------------------------------     let displaySemInput (TestCase { tcSem = si, tcSemString = str }) =-           geniShow $ toSemInputString si str-     let onTestCaseChoice = do-         csel <- get caseChoice selection-         if boundsCheck csel suite-           then do let s = (suiteCases !! csel)-                   set tsBox [ text :~ (\_ -> displaySemInput s) ]-           else geniBug $ "Gui: test case selector bounds check error: " ++-                          show csel ++ " of " ++ show tcaseLabels ++ "\n"-     -----------------------------------------------------     set caseChoice [ items := tcaseLabels -                  , selection := caseSel-                  , on select := onTestCaseChoice ]-     when (not $ null suite) onTestCaseChoice -- run this once-\end{code}- -% ---------------------------------------------------------------------\section{Configuration}-% ----------------------------------------------------------------------The configuration GUI aims to a provide a graphical substitute for the command-line switches.  Note you cannot yet select optimisations and test cases from-this window; use the main window instead.  Note also that changes to GenI tend-to start from the command line switches and only percolate to the GUI when time-permits.  For full control of GenI, see \verb!geni --help!.--\begin{center}-\emph{TODO: screenshot wanted}-\end{center}--\begin{code}--- | 'configGui' @pstRef loadFn@ provides the configuration GUI. The continuation---   @loadFn@ tells us what to do when the user closes this window.-configGui ::  ProgStateRef -> IO () -> IO () -configGui pstRef loadFn = do -  pst <- readIORef pstRef-  let config = pa pst-  -- -  f  <- frame []-  p  <- panel f []-  nb <- notebook p []-  let browseTxt = "Browse"-  ---  let fakeBoxed title lst = hstretch $ column 3 $ map hfill $ -        [ hrule 1 , alignRight $ label title, vspace 5 ] -        ++ map hfill lst-  let shortSize = sz 10 25-  let longSize  = sz 20 25-  -- ------------------------------------------------------------------  -- basic options tab-  -- ------------------------------------------------------------------  pbas <- panel nb []-  -- files loaded (labels)-  macrosFileLabel  <- staticText pbas [ text := getListFlagP MacrosFlg config  ]-  lexiconFileLabel <- staticText pbas [ text := getListFlagP LexiconFlg config ]-  tsFileLabel      <- staticText pbas [ text := getListFlagP TestSuiteFlg config ]-  -- "Browse buttons"-  macrosBrowseBt  <- button pbas [ text := browseTxt ]-  lexiconBrowseBt <- button pbas [ text := browseTxt ]-  tsBrowseBt      <- button pbas [ text := browseTxt ]-  -- root feature-  rootFeatTxt <- entry pbas-    [ text := showFlist $ getListFlagP RootFeatureFlg config-    , size := longSize ]-  let layFiles = [ row 1 [ label "trees:" -                         , fill $ widget macrosFileLabel-                         , widget macrosBrowseBt  ]-                 , row 1 [ label "lexicon:"-                         , fill $ widget lexiconFileLabel-                         , widget lexiconBrowseBt ] -                 , row 1 [ label "test suite:"-                         , fill $ widget tsFileLabel-                         , widget tsBrowseBt ]-                 , hspace 5-                 , hfill $ vrule 1-                 , row 3 [ label "root features"-                         , hglue-                         , rigid $ widget rootFeatTxt ]  -                 ] -    -- the layout for the basic stuff-  let layBasic = dynamic $ container pbas $ -- boxed "Basic options" $ -                   hfloatLeft $ dynamic $ fill $ column 4 $ map (dynamic.hfill) $ layFiles -  -- ------------------------------------------------------------------  -- advanced options tab-  -- ------------------------------------------------------------------  padv <- panel nb []-  -- XMG tools -  viewCmdTxt <- entry padv -    [ tooltip := "Command used for XMG tree viewing"-    , text := getListFlagP ViewCmdFlg config ]-  let layXMG = fakeBoxed "XMG tools" -                [ row 3 [ label "XMG view command"-                        , marginRight $ hfill $ widget viewCmdTxt ] ]-  -- polarities-  extraPolsTxt <- entry padv -    [ text := maybe "" showLitePm $ getFlagP ExtraPolaritiesFlg config-    , size := shortSize ]-  let layPolarities = fakeBoxed "Polarities" [ hfill $ row 1 -          [ label "extra polarities", rigid $ widget extraPolsTxt ] ]-  -- morphology-  morphFileLabel    <- staticText padv [ text := getListFlagP MorphInfoFlg config ]-  morphFileBrowseBt <- button padv [ text := browseTxt ]-  morphCmdTxt    <- entry padv -    [ tooltip := "Commmand used for morphological generation" -    , text    := getListFlagP MorphCmdFlg config ]-  let layMorph = fakeBoxed "Morphology" -                   [ row 3 [ label "morph info:"-                           , expand $ hfill $ widget morphFileLabel-                           , widget morphFileBrowseBt ]-                   , row 3 [ label "morph command"-                           , (marginRight.hfill) $ widget morphCmdTxt ] ]-  -- put the whole darn thing together-  let layAdvanced = hfloatLeft $ container padv $ column 10 -        $ [ layXMG, layPolarities, layMorph]-  -- ------------------------------------------------------------------  -- browse button action-  ---  -- When the user clicks on a Browse button, an open file dialogue should pop up.-  -- It gets its value from the file label on its left (passed in as an argument),-  -- and updates said label when the user has made a selection.-  -- ------------------------------------------------------------------  -- helper functions-  curDir <- getCurrentDirectory-  let curDir2 = curDir ++ "/"-      trim2 pth = if curDir2 `isPrefixOf` pth2-                     then drop (length curDir2) pth2-                     else pth2-                  where pth2 = trim pth-  let onBrowse theLabel -       = do rawFilename <- get theLabel text-            let filename = trim2 rawFilename-                filetypes = [("Any file",["*","*.*"])]-            fsel <- fileOpenDialog f False True-                      "Choose your file..." filetypes "" filename-            case fsel of-              -- if the user does not select any file there are no changes-              Nothing   -> return () -              Just file -> set theLabel [ text := trim2 file ]-  -- end onBrowse-  -- activate those "Browse" buttons-  let setBrowse w l = set w [ on command := onBrowse l ]-  setBrowse macrosBrowseBt macrosFileLabel-  setBrowse lexiconBrowseBt lexiconFileLabel -  setBrowse tsBrowseBt tsFileLabel-  setBrowse morphFileBrowseBt morphFileLabel-  -- ------------------------------------------------------------------  -- config GUI layout-  -- ------------------------------------------------------------------  let parsePol = parseFlagWithParsec "polarities"    geniPolarities-      parseRF  = parseFlagWithParsec "root features" geniFeats-      onLoad -       = do macrosVal <- get macrosFileLabel text-            lexconVal <- get lexiconFileLabel text-            tsVal     <- get tsFileLabel text-            ---            rootCatVal  <- get rootFeatTxt  text-            extraPolVal <- get extraPolsTxt text-            ---            viewVal   <- get viewCmdTxt text -            ---            morphCmdVal  <- get morphCmdTxt text-            morphInfoVal <- get morphFileLabel text-            ---            let maybeSet fl fn x =-                   if null x then deleteFlagP fl else setFlagP fl (fn x)-                maybeSetStr fl x = maybeSet fl id x-            let setConfig = id-                  . (maybeSetStr   MacrosFlg macrosVal)-                  . (maybeSetStr LexiconFlg lexconVal)-                  . (maybeSetStr TestSuiteFlg tsVal)-                  . (maybeSetStr TestInstructionsFlg [(tsVal,Nothing)])-                  . (maybeSet RootFeatureFlg parseRF rootCatVal)-                  . (maybeSet ExtraPolaritiesFlg parsePol extraPolVal)-                  . (maybeSetStr ViewCmdFlg viewVal)-                  . (maybeSetStr MorphCmdFlg morphCmdVal)-                  . (maybeSetStr MorphInfoFlg morphInfoVal)-            modifyIORef pstRef $ \x -> x { pa = setConfig (pa x) }-            loadFn -  -- end onLoad-    -- the button bar-  cancelBt <- button p -    [ text := "Cancel", on command := close f ]-  loadBt   <- button p -    [ text := "Load", on command := do { onLoad; close f } ]-  let layButtons = hfill $ row 1 -        [ hfloatLeft  $ widget cancelBt-        , hfloatRight $ widget loadBt ]-  ---  set f [ layout := dynamic $ fill $ container p $ column 0 -           [ fill $ tabs nb [ tab "Basic" layBasic-                            , tab "Advanced" layAdvanced ] -           , hfill $ layButtons ]-        ] -\end{code}- -% ---------------------------------------------------------------------\section{Generation}-% ----------------------------------------------------------------------\begin{code}--- | 'doGenerate' parses the target semantics, then calls the generator and--- displays the result in a results gui (below).-doGenerate :: Textual b => Window a -> ProgStateRef -> b -> Bool -> Bool -> IO ()-doGenerate f pstRef sembox useDebugger pauseOnLex =- do loadEverything pstRef-    sem <- get sembox text-    loadTargetSemStr pstRef sem-    ---    pst <- readIORef pstRef-    let config = pa pst-        withBuilderGui a =-          case builderType config of-          NullBuilder   -> error "No gui available for NullBuilder"-          SimpleBuilder         -> a simpleGui_2p-          SimpleOnePhaseBuilder -> a simpleGui_1p-    ---    let doDebugger bg = debugGui bg pstRef pauseOnLex-        doResults  bg = resultsGui bg pstRef-    do catch (withBuilderGui $ if useDebugger then doDebugger else doResults)-             (handler "Error during realisation")-  -- FIXME: it would be nice to distinguish between generation and ts-  -- parsing errors- `catch` (handler "Error parsing the input semantics")- where-   handler title err = errorDialog f title (show err)-\end{code}--When surface realisation is complete, we display a results window with various-tabs for intermediary results in lexical selection, derived trees, derivation-trees and generation statistics.--\begin{center}-\emph{TODO: screenshot wanted}-\end{center}--\begin{code}-resultsGui :: BG.BuilderGui -> ProgStateRef -> IO ()-resultsGui builderGui pstRef =- do -- results window-    f <- frame [ text := "Results"-               , fullRepaintOnResize := False-               , layout := stretch $ label "Generating..."-               , clientSize := sz 300 300-               ]-    p    <- panel f []-    nb   <- notebook p []-    -- realisations tab-    (results,stats,resTab) <- BG.resultsPnl builderGui pstRef nb-    -- summary tab-    let sentences = concatMap grRealisations results-    summTab <- statsGui nb sentences stats-    -- ranking tab-    pst <- readIORef pstRef-    let useRanking = hasFlagP RankingConstraintsFlg (pa pst)-    rankTab <- messageGui nb . unlines . map (prettyResult pst) $ results-    -- tabs-    let myTabs = [ tab "summary"       summTab-                 , tab "realisations"  resTab-                 ] ++-                 (if useRanking then [ tab "ranking" rankTab ] else [])-    -- pack it all together-    set f [ layout := container p $ column 0 [ tabs nb myTabs ]-          , clientSize := sz 700 600 ]-    return ()---- | 'statsGui' displays the generation statistics and provides a--- handy button for saving results to a text file.-statsGui :: (Window a) -> [String] -> Statistics -> IO Layout-statsGui f sentences stats =-  do let msg = showRealisations sentences-     ---     p <- panel f []-     t  <- textCtrl p [ text := msg, enabled := False ]-     statsTxt <- staticText p [ text := showFinalStats stats ]-     ---     saveBt <- button p [ text := "Save to file"-                        , on command := maybeSaveAsFile f msg ]-     return $ fill $ container p $ column 1 $-              [ hfill $ label "Performance data"-              , hfill $ widget statsTxt-              , hfill $ label "Realisations"-              , fill  $ widget t-              , hfloatRight $ widget saveBt ]-\end{code}--% ---------------------------------------------------------------------\section{Debugging}-\label{sec:gui:debugger}-% ----------------------------------------------------------------------Instead of going directly to the results window, you could instead use the-interactive debugger which GenI provides.  The debugger shows a separate tab-for each phase in surface realisation (lexical selection, filtering, building).--\begin{center}-\includegraphics[width=0.47\textwidth]{hcar/GenI-debugger-screenshot.jpg}-\end{center}--\begin{code}--- | We provide here a universal debugging interface, which makes use of some---   parameterisable bits as defined in the BuilderGui module.-debugGui :: BG.BuilderGui -> ProgStateRef -> Bool -> IO ()-debugGui builderGui pstRef pauseOnLex =- do pst <- readIORef pstRef-    let config = pa pst-        btype = show $ builderType config-    ---    f <- frame [ text := "GenI Debugger - " ++ btype ++ " edition"-               , fullRepaintOnResize := False-               , clientSize := sz 300 300 ]-    p    <- panel f []-    nb   <- notebook p []-    -- generation step 1-    initStuff <- initGeni pstRef-    let (cand,_)   = unzip $ B.inCands initStuff-    -- continuation for candidate selection tab-    let step2 newCands =-         do -- generation step 2.A (run polarity stuff)-            let newInitStuff = initStuff { B.inCands = map (\x -> (x, -1)) newCands }-                (input2, _, autstuff) = B.preInit newInitStuff config-            -- automata tab-            let (auts, _, finalaut, _) = autstuff-            autPnl <- if hasOpt Polarised config-                         then fst3 `fmap` polarityGui nb auts finalaut-                         else messageGui nb "polarity filtering disabled"-            -- generation step 2.B (start the generator for each path)-            debugPnl <- BG.debuggerPnl builderGui nb config input2 btype-            let autTab   = tab "automata" autPnl-                debugTab = tab (btype ++ "-session") debugPnl-                genTabs  = if hasOpt Polarised config-                           then [ autTab, debugTab ] else [ debugTab ]-            ---            set f [ layout := container p $ tabs nb genTabs-                  , clientSize := sz 700 600 ]-            return ()-    -- candidate selection tab-    (canPnl,_,_) <- if pauseOnLex-                    then pauseOnLexGui pst nb cand step2-                    else candidateGui  pst nb cand-    -- basic tabs-    let basicTabs = [ tab "lexical selection" canPnl ]-    ---    set f [ layout := container p $ tabs nb basicTabs-          , clientSize := sz 700 600 ]-    -- display all tabs if we are not told to pause on lex selection-    when (not pauseOnLex) (step2 cand)-\end{code}--\subsection{Stepping through the debugger}--The interactive debugger can have a diffrent GUI for each realisation algorithm.-Here we will discuss the interface for the Simple 2-Phase algorithm which \geni-uses by default.  The interfaces for other algorithms are likely to very similar.--\begin{center}-\includegraphics[width=0.47\textwidth]{images/debugger-features.png}-\end{center}--The debugger allows you to step through chart generation.  Using the 'Step by'-button, you can walk through an arbitrary number of steps, where each step-consists in pulling one item of the agenda, combining it with the chart and-putting some of the results back on to the agenda (or the trash, or results-pile as the case may be).  New chart items produced on each step typically have-one of their nodes highlighted in red.  This indicates that the node was the-site of the most recent ``event''.  For example in the substitution phase, the-red node indicates where the substitution operation was performed; whereas in-the adjunction phase, it could either indicate where adjunction was performed-or where a null-adjunction constraint was applied.--If you select the ``show features'' checkbox, all nodes in the chart item will-be expanded to reveal the underlying feature structures.  The components of this-expanded representation are segmented into the following boxes:--\vspace{1em}-\begin{tabular}{ll}-\begin{minipage}{0.10\textwidth}-\includegraphics[width=\textwidth]{images/debugger-features-focus.png}-\end{minipage} &-\begin{minipage}{0.70\textwidth}-\begin{enumerate}-\item Summary: here, \verb!n:j.m! indicates that the category is \verb!n!,-      that the top \verb!idx! feature is associated with \verb'j' and the-      bottom one with \verb!m!.-\item Decorations: here, $\downarrow$ indicates that this is a TAG substitution-      node, following the usual conventions in the literature.-\item The top feature structure-\item The bottom feature structure-\end{enumerate}-\end{minipage} \\-\end{tabular}--% ---------------------------------------------------------------------\section{Tree browser}-\label{sec:treebrowser_gui}-% ----------------------------------------------------------------------The GenI tree browser displays all the TAG trees in the grammar grouped-according to the semantics with which they are associated.--\begin{code}--- Note that we can't just reuse candidateGui's code because we label and sort--- the trees differently.  Here we ignore the arguments in tree semantics, and--- we display the tree polarities in its label.-treeBrowserGui :: ProgStateRef -> IO () -treeBrowserGui pstRef = do-  pst <- readIORef pstRef-  -- ALL THE TREES in the grammar... muahahaha!-  let semmap = combine (gr pst) (le pst)-  -- browser window-  f <- frame [ text := "Tree Browser" -             , fullRepaintOnResize := False -             ] -  -- the heavy GUI artillery-  let sem      = Map.keys semmap-      ---      lookupTr k = Map.findWithDefault [] k semmap-      treesfor k = Nothing : (map Just $ lookupTr k)-      labsfor  k = ("___" ++ k ++ "___") : (map fn $ lookupTr k)-                   where fn    t = idname t ++ polfn (tpolarities t)-                         polfn p = if Map.null p -                                   then "" -                                   else " (" ++ showLitePm p ++ ")"-      ---      trees    = concatMap treesfor sem-      itNlabl  = zip trees (concatMap labsfor sem)-  (browser,_,_) <- tagViewerGui pst f "tree browser" "grambrowser" itNlabl-  -- the button panel-  let count = length trees - length sem-  quitBt <- button f [ text := "Close", on command := close f ]-  -- pack it all together -  set f [ layout := column 5 [ browser, -                       row 5 [ label ("number of trees: " ++ show count)-                             , hfloatRight $ widget quitBt ] ]-        , clientSize := sz 700 600 ]-  return ()-\end{code}
− src/NLP/GenI/GuiHelper.hs
@@ -1,750 +0,0 @@--- GenI surface realiser--- Copyright (C) 2005 Carlos Areces and Eric Kow------ This program is free software; you can redistribute it and/or--- modify it under the terms of the GNU General Public License--- as published by the Free Software Foundation; either version 2--- of the License, or (at your option) any later version.------ This program is distributed in the hope that it will be useful,--- but WITHOUT ANY WARRANTY; without even the implied warranty of--- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the--- GNU General Public License for more details.------ You should have received a copy of the GNU General Public License--- along with this program; if not, write to the Free Software--- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.--{-# LANGUAGE FlexibleContexts #-}-module NLP.GenI.GuiHelper where--import Graphics.UI.WX--- import Graphics.UI.WXCore--import Control.Arrow ( (&&&), (***) )-import qualified Control.Monad as Monad -import Control.Monad.State.Strict ( execStateT, runState )-import qualified Data.Map as Map--import Data.IORef-import System.Directory -import System.FilePath ((<.>),(</>),dropExtensions)-import System.Process (runProcess)-import Text.ParserCombinators.Parsec (parseFromFile)--import NLP.GenI.Graphviz-import NLP.GenI.Automaton (numStates, numTransitions)--import NLP.GenI.Configuration ( getFlagP, MacrosFlg(..), ViewCmdFlg(..) )-import NLP.GenI.GeniShow(geniShow)-import NLP.GenI.GraphvizShow ()-import NLP.GenI.Tags (TagItem(tgIdName), tagLeaves)-import NLP.GenI.Geni-  ( ProgState(..) )-import NLP.GenI.GeniParsers ( geniTagElems )-import NLP.GenI.General-  (geniBug, boundsCheck, dropTillIncluding, ePutStrLn)-import NLP.GenI.Btypes-  ( showAv, showPred, showLexeme, )-import NLP.GenI.PolarityTypes ( PolarityKey(..) )-import NLP.GenI.Tags-  ( idname, mapBySem, TagElem(ttrace, tinterface) )--import NLP.GenI.Configuration-  ( Params(..), MetricsFlg(..), setFlagP )--import qualified NLP.GenI.Builder as B-import NLP.GenI.Builder (queryCounter, num_iterations, chart_size,-    num_comparisons)-import NLP.GenI.Polarity (PolAut, detectPolFeatures)-import NLP.GenI.GraphvizShowPolarity ()---- ------------------------------------------------------------------------- Types--- ------------------------------------------------------------------------data GraphvizStatus = GvError String-                    | GvNoSuchItem Int-                    | GvCached-                    | GvCreated FilePath-  deriving Show---- ------------------------------------------------------------------------- Lexically selected items--- -------------------------------------------------------------------------- | 'candidateGui' displays the lexically selected items, grouped by the---   semantics they subsume.-candidateGui :: ProgState-             -> Window a-             -> [TagElem]-             -> GvIO () Bool (Maybe TagElem)-candidateGui pst f xs = do-  p  <- panel f []      -  (tb,gvRef,updater) <- tagViewerGui pst p "lexically selected item" "candidates"-                        $ sectionsBySem xs-  let polFeats = "Polarity attributes detected: " ++ (unwords.detectPolFeatures) xs-      warning = unlines $ filter (not.null) (polFeats : warnings pst)-  -- side panel-  sidePnl <- panel p []-  ifaceLst <- singleListBox sidePnl [ tooltip := "interface for this tree (double-click me!)" ]-  traceLst <- singleListBox sidePnl [ tooltip := "trace for this tree (double-click me!)" ]-  tNoted <- textCtrl sidePnl [ wrap := WrapWord, text := "Hint: copy from below and paste into the sem:\n" ]-  let laySide = container sidePnl $ column 2-                  [ label "interface"-                  ,  fill $ widget ifaceLst-                  , label "trace"-                  ,  fill $ widget traceLst-                  , label "notes"-                  ,  fill $ widget tNoted ]-  -- handlers-  let addLine :: String -> String -> String-      addLine x y = y ++ "\n" ++ x-      ---      addToNoted w =-        do sel    <- get w selection-           things <- get w items-           when (sel > 0) $ set tNoted [ text :~ addLine (things !! sel) ]-  set ifaceLst [ on doubleClick := \_ -> addToNoted ifaceLst ]-  set traceLst [ on doubleClick := \_ -> addToNoted traceLst ]-  -- updaters : what happens when the user selects an item-  let updateTrace = gvOnSelect (return ())-        (\s -> set traceLst [ items := ttrace s ])-      updateIface = gvOnSelect (return ())-        (\s -> set ifaceLst [ items := map showAv $ tinterface s ])-  Monad.unless (null xs) $ do-    addGvHandler gvRef updateTrace-    addGvHandler gvRef updateIface-    -- first time run-    gvSt <- readIORef gvRef-    updateIface gvSt-    updateTrace gvSt-  ---  let layMain = fill $ row 2 [ fill tb, vfill laySide ]-      theItems = if null warning then [ layMain ] else [ hfill (label warning) , layMain ]-      lay  = fill $ container p $ column 5 theItems-  return (lay, gvRef, updater)--sectionsBySem :: (TagItem t) => [t] -> [ (Maybe t, String) ]-sectionsBySem tsem =- let semmap   = mapBySem tsem-     sem      = Map.keys semmap-     ---     lookupTr k = Map.findWithDefault [] k semmap-     section  k = (Nothing, header) : (map tlab $ lookupTr k)-                  where header = "___" ++ showPred k ++ "___"-                        tlab t = (Just t, tgIdName t)- in concatMap section sem---- ------------------------------------------------------------------------- Polarity Automata--- -------------------------------------------------------------------------- | A browser to see the automata constructed during the polarity optimisation---   step.-polarityGui :: (Window a) -> [(PolarityKey,PolAut,PolAut)] -> PolAut-            -> GvIO () () PolAut-polarityGui   f xs final = do-  let stats a = " (" ++ (show $ numStates a) ++ "st " ++ (show $ numTransitions a) ++ "tr)"-      aut2  (_ , a1, a2)  = [ a1, a2 ]-      autLabel (PolarityKey fv,a1,a2) = [ fv ++ stats a1, fv ++ " pruned" ++ stats a2]-      finalAutLab = ( final, "final" ++ stats final )-      autslabs = concatBoth (map (aut2 &&& autLabel) xs) ++ [ finalAutLab ]-  gvRef   <- newGvRef () () "automata"-  setGvDrawables gvRef autslabs-  graphvizGui f "polarity" gvRef--concatBoth :: [ ([a],[b]) ] -> [ (a,b) ]-concatBoth = uncurry zip . (concat *** concat) . unzip -- is there a simpler way?---- ------------------------------------------------------------------------- Helpers--- -----------------------------------------------------------------------      --- | Any data structure which has corresponds to a TAG tree and which---   has some notion of derivation-class XMGDerivation a where-  getSourceTrees :: a -> [String]--instance XMGDerivation TagElem where-  getSourceTrees te = [idname te]---- | 'toSentence' almost displays a 'TagElem' as a sentence, but only good--- enough for debugging needs.  The problem is that each leaf may be--- an atomic disjunction. Our solution is just to display each choice and--- use some delimiter to seperate them.  We also do not do any--- morphological processing.-toSentence :: TagElem -> String-toSentence = unwords . map squishLeaf . tagLeaves--squishLeaf :: (a,([String], b)) -> String-squishLeaf = showLexeme.fst.snd---- ------------------------------------------------------------------------- TAG viewer--- -------------------------------------------------------------------------- | Variant of 'graphvizGui' with a toggle to view feature structures-tagViewerGui :: (GraphvizShow Bool t, TagItem t, XMGDerivation t)-             => ProgState -> (Window a) -> String -> String -> [(Maybe t,String)]-             -> GvIO () Bool (Maybe t)-tagViewerGui pst f tip cachedir itNlab = do-  p <- panel f []      -  gvRef <- newGvRef () False tip-  setGvDrawables gvRef itNlab-  (lay,ref,onUpdate) <- graphvizGui p cachedir gvRef-  -- button bar widgets-  detailsChk <- checkBox p [ text := "Show features"-                           , checked := False ]-  viewTagLay <- viewTagWidgets p gvRef (pa pst)-  -- handlers-  let onDetailsChk =-        do isDetailed <- get detailsChk checked-           setGvParams gvRef isDetailed-           onUpdate-  set detailsChk [ on command := onDetailsChk ]-  -- pack it all in      -  let cmdBar = hfill $ row 5 -                [ dynamic $ widget detailsChk-                , viewTagLay ]-      lay2   = fill $ container p $ column 5 [ fill lay, cmdBar ]-  return (lay2,ref,onUpdate)---- ------------------------------------------------------------------------- XMG Metagrammar stuff.--- See <http://sourcesup.cru.fr/xmg/>--- -------------------------------------------------------------------------- | Calls Yannick Parmentier's handy visualisation tool ViewTAG.-viewTagWidgets :: (GraphvizShow Bool t, TagItem t, XMGDerivation t)-               => Window a -> GraphvizGuiRef st (Maybe t) Bool -> Params-               -> IO Layout-viewTagWidgets p gvRef config =- do viewTagBtn <- button p [ text := "ViewTAG" ]-    viewTagCom <- choice p [ tooltip := "derivation tree" ]-    -- handlers-    let onViewTag = readIORef gvRef >>=-         gvOnSelect (return ())-           (\t -> do let derv = getSourceTrees t-                     ds <- get viewTagCom selection-                     if boundsCheck ds derv-                        then runViewTag config (derv !! ds)-                        else geniBug $ "Gui: bounds check in onViewTag"-           )-    set viewTagBtn [ on command := onViewTag ]-    -- when the user selects a tree, we want to update the list of derivations-    let updateDerivationList = gvOnSelect-          (set viewTagCom [ enabled := False ])-          (\s -> set viewTagCom [ enabled := True-                                , items := getSourceTrees s-                                , selection := 0] )-    addGvHandler gvRef updateDerivationList-    updateDerivationList =<< readIORef gvRef-    ---    return $ row 5 $ map dynamic [ widget viewTagCom, widget viewTagBtn ]--runViewTag :: Params -> String -> IO ()-runViewTag params drName =-  case getFlagP MacrosFlg params of-  Nothing -> ePutStrLn "Warning: No macros files specified (runViewTag)"-  Just f  -> do-     -- figure out what grammar file to use-     let gramfile = dropExtensions f <.> "rec"-         treenameOnly = takeWhile (/= ':') . dropTillIncluding ':' . dropTillIncluding ':'-     -- run the viewer-     case getFlagP ViewCmdFlg params of-       Nothing -> ePutStrLn "Warning: No viewcmd specified (runViewTag)"-       Just c  -> do -- run the viewer-                     runProcess c [gramfile, treenameOnly drName]-                       Nothing Nothing Nothing Nothing Nothing-                     return ()---- ----------------------------------------------------------------------- Graphical debugger (helper functions)--- ------------------------------------------------------------------------ | 'pauseOnLexGui' allows the user to see lexical selection only and either---   dump it to file or read replace it by the contents of some other file-pauseOnLexGui :: ProgState -> (Window a) -> [TagElem]-              -> ([TagElem] -> IO ()) -- ^ continuation-              -> GvIO () Bool (Maybe TagElem)-pauseOnLexGui pst f xs job = do-  p <- panel f []-  candV <- varCreate xs-  (tb, ref, updater) <- candidateGui pst p xs-  -- supplementary button bar-  let saveCmd =-       do c <- varGet candV-          let cStr = unlines $ map geniShow c-          maybeSaveAsFile f cStr-      loadCmd =-       do let filetypes = [("Any file",["*","*.*"])]-          fsel <- fileOpenDialog f False True "Choose your file..." filetypes "" ""-          case fsel of-           Nothing   -> return ()-           Just file ->-             do parsed <- parseFromFile geniTagElems file-                case parsed of-                 Left err -> errorDialog f "" (show err)-                 Right c  -> do varSet candV c-                                setGvDrawables ref (sectionsBySem c)-                                updater-  ---  saveBt <- button p [ text := "Save to file", on command := saveCmd ]-  loadBt <- button p [ text := "Load from file", on command := loadCmd ]-  nextBt <- button p [ text := "Begin" ]-  let disableW w = set w [ enabled := False ]-  set nextBt [ on command := do mapM disableW [ saveBt, loadBt, nextBt ]-                                varGet candV >>= job ]-  ---  let lay = fill $ container p $ column 5-            [ fill tb, hfill (vrule 1)-            , row 0 [ row 5 [ widget saveBt, widget loadBt ]-                    , hfloatRight $ widget nextBt ] ]-  return (lay, ref, updater)--type DebuggerItemBar st flg itm-      =  Panel ()                     -- ^ parent panel-      -> GraphvizGuiRef st (Maybe itm) flg  -- ^ gv ref to use-      -> GvUpdater -- ^ onUpdate-      -> IO (Layout, GvUpdater)---- | A generic graphical debugger widget for GenI, including------   * item viewer which allows the user to select one of the items in the---     builder state.------   * item bar which provides some options on how to view the currently---     selected item, for example, if you want to display the features or not.------   * A dashboard which lets the user do things like ``go ahead 6 steps''.--- ---   Besides the Builder, there are two functions you need to pass in make this---   work: ------      1. a 'stateToGv' which converts the builder state into a list of items---         and labels the way 'graphvizGui' likes it------      2. an 'item bar' function which lets you control what bits you display---         of a selected item (for example, if you want a detailed view or not)---         the item bar should return a layout ------   Note that we don't constrain the type of item returned by the builder to---   be the same as the type handled by your gui: that's quite normal because---   you might want to decorate the type with some other information-debuggerPanel :: (GraphvizShow flg itm) -  => B.Builder st itm2 Params -- ^ builder to use-  -> flg -- ^ initial value for the flag argument in GraphvizShow-  -> (st -> [(Maybe itm, String)])-     -- ^ function to convert a Builder state into lists of items-     --   and their labels, the way graphvizGui likes it-  -> (DebuggerItemBar st flg itm)-     -- ^ 'itemBar' function returning a control panel configuring-     --   how you want the currently selected item in the debugger-     --   to be displayed-  -> (Window a) -- ^ parent window-  -> Params     -- ^ geni params-  -> B.Input    -- ^ builder input-  -> String     -- ^ graphviz cache directory-  -> IO Layout -debuggerPanel builder gvInitial stateToGv itemBar f config input cachedir = - do let initBuilder = B.init  builder -        nextStep    = B.step  builder -        allSteps    = B.stepAll builder -        ---    let (initS, initStats) = initBuilder input config2-        config2 = setFlagP MetricsFlg (B.defaultMetricNames) config-    p <- panel f []      -    -- ----------------------------------------------------------    -- item viewer: select and display an item-    -- ----------------------------------------------------------    gvRef <- newGvRef initS gvInitial "debugger session"-    setGvDrawables gvRef (stateToGv initS)-    (layItemViewer,_,onUpdateMain) <- graphvizGui p cachedir gvRef-    -- -----------------------------------------------------------    -- item bar: controls for how an individual item is displayed-    -- -----------------------------------------------------------    (layItemBar,onUpdateItemBar) <- itemBar p gvRef onUpdateMain-    -- ------------------------------------------- -    -- dashboard: controls for the debugger itself -    -- ------------------------------------------- -    let onUpdate = onUpdateMain >> onUpdateItemBar-    db <- panel p []-    restartBt <- button db [text := "Start over"]-    nextBt    <- button db [text := "Step by..."]-    leapVal   <- entry  db [ text := "1", clientSize := sz 30 25 ]-    finishBt  <- button db [text := "Leap to end"]-    statsTxt  <- staticText db []-    -- dashboard commands-    let showQuery c gs = case queryCounter c gs of-                         Nothing -> "???"-                         Just q  -> show q-        updateStatsTxt gs = set statsTxt [ text :~ (\_ -> txtStats gs) ]-        txtStats   gs =  unwords [ "itr",  showQuery num_iterations gs-                                 , "chart sz", showQuery chart_size gs-                                 ]-                      ++ "\ncomparisons: " ++ showQuery num_comparisons gs-    let genStep _ (st,stats) = runState (execStateT nextStep st) stats-    let showNext s_stats = -          do leapTxt <- get leapVal text-             let leapInt :: Integer-                 leapInt = read leapTxt-                 (s2,stats2) = foldr genStep s_stats [1..leapInt]-             modifyIORef gvRef $ \g -> g { gvcore = s2 }-             setGvDrawables gvRef (stateToGv s2)-             setGvSel gvRef 1-             onUpdate-             updateStatsTxt stats2-             set nextBt [ on command :~ (\_ -> showNext (s2,stats2) ) ]-    let showLast = -          do -- redo generation from scratch-             let (s2, stats2) = runState (execStateT allSteps initS) initStats -             setGvDrawables gvRef (stateToGv s2)-             onUpdate-             updateStatsTxt stats2-    let showReset = -          do set nextBt   [ on command  := showNext (initS, initStats) ]-             updateStatsTxt initStats -             setGvDrawables gvRef (stateToGv initS)-             setGvSel gvRef 1-             onUpdate-    -- dashboard handlers-    set finishBt  [ on command := showLast ]-    set restartBt [ on command := showReset ]-    showReset-    -- dashboard layout  -    let layCmdBar = hfill $ container db $ row 5-                     [ widget statsTxt, hfloatRight $ row 5 -                       [ widget restartBt, widget nextBt -                       , widget leapVal, label " step(s)"-                       , widget finishBt ] ]-    -- ------------------------------------------- -    -- overall layout-    -- ------------------------------------------- -    return $ fill $ container p $ column 5 [ layItemViewer, layItemBar, hfill (vrule 1), layCmdBar ] ---- ----------------------------------------------------------------------- Graphviz GUI--- -----------------------------------------------------------------------data GraphvizOrder = GvoParams | GvoItems | GvoSel -     deriving Eq--data GraphvizGuiSt st a b =-        GvSt { gvcore    :: st,-               gvitems   :: Map.Map Int a,-               gvparams  :: b,-               gvlabels  :: [String],-               -- | tooltip for the selection box-               gvtip     :: String,-               -- | handler function to call when the selection is-               -- updated (note: before displaying the object)-               gvhandler :: Maybe (GraphvizGuiSt st a b -> IO ()),-               gvsel     :: Int,-               gvorders  :: [GraphvizOrder] }---- | This provides a mechanism for communicating with the GUI.  The basic idea:------  1. you create a GvRef with newGvRef------  2. you call 'graphvizGui' and get back an updater function------  3. whenever you want to modify something, you use setGvWhatever and call---     the updater function------  4. if you want to react to the selection being changed, you should set---     gvhandler-type GraphvizGuiRef st a b = IORef (GraphvizGuiSt st a b)--newGvRef :: st -> b -> String -> IO (GraphvizGuiRef st a b)-newGvRef initSt p t =-  let st = GvSt { gvcore = initSt,-                  gvparams = p,-                  gvitems  = Map.empty,-                  gvlabels  = [], -                  gvhandler = Nothing,-                  gvtip    = t,-                  gvsel    = 0,-                  gvorders = [] }-  in newIORef st--setGvSel :: GraphvizGuiRef st a b  -> Int -> IO ()-setGvSel gvref s  =-  do let fn x = x { gvsel = s,-                    gvorders = GvoSel : (gvorders x) }-     modifyIORef gvref fn -  -setGvParams :: GraphvizGuiRef st a b -> b -> IO ()-setGvParams gvref c  =-  do let fn x = x { gvparams = c,-                    gvorders = GvoParams : (gvorders x) }-     modifyIORef gvref fn --modifyGvParams :: GraphvizGuiRef st a b -> (b -> b) -> IO ()-modifyGvParams gvref fn  =-  do gvSt <- readIORef gvref-     setGvParams gvref (fn $ gvparams gvSt)--setGvDrawables :: GraphvizGuiRef st a b -> [(a,String)] -> IO ()-setGvDrawables gvref itlb =-  do let (it,lb) = unzip itlb-         fn x = x { gvitems = Map.fromList $ zip [0..] it-                  , gvlabels = lb-                  , gvorders = GvoItems : (gvorders x)-                  }-     modifyIORef gvref fn ---- | Helper function for making selection handlers (see 'addGvHandler')---   Note that this was designed for cases where the contents is a Maybe-gvOnSelect :: IO () -> (a -> IO ()) -> GraphvizGuiSt st (Maybe a) b -> IO ()-gvOnSelect onNothing onJust gvSt =- let sel    = gvsel gvSt-     things = gvitems gvSt- in case Map.lookup sel things of-    Just (Just s) -> onJust s-    _             -> onNothing--setGvHandler :: GraphvizGuiRef st a b -> Maybe (GraphvizGuiSt st a b -> IO ()) -> IO ()-setGvHandler gvref mh =-  do gvSt <- readIORef gvref-     modifyIORef gvref (\x -> x { gvhandler = mh })-     case mh of -       Nothing -> return ()-       Just fn -> fn gvSt---- | add a selection handler - if there already is a handler---   this handler will be called before the new one-addGvHandler :: GraphvizGuiRef st a b -> (GraphvizGuiSt st a b -> IO ()) -> IO ()-addGvHandler gvref h =-  do gvSt <- readIORef gvref-     let newH = case gvhandler gvSt of -                Nothing   -> Just h-                Just oldH -> Just (\g -> oldH g >> h g)-     setGvHandler gvref newH--type GvIO st f d  = IO (Layout, GraphvizGuiRef st d f, GvUpdater)-type GvUpdater = IO ()---- |'graphvizGui' @f glab cachedir gvRef@ is a general-purpose GUI for--- displaying a list of items graphically via AT&T's excellent Graphviz--- utility.  We have a list box where we display all the labels the user--- provided.  If the user selects an entry from this box, then the item--- corresponding to that label will be displayed.------ This returns a layout (wxhaskell container) and a function that you're--- expected to call whever something changes that would require the GUI to--- refresh itself (for example, you create a new chart item)------  * @f@ - (parent window) the GUI is provided as a panel within the parent.---    Note: we use window in the WxWidget's sense, meaning it could be---    anything as simple as a another panel, or a notebook tab.---  * @glab@ - (gui labels) a tuple of strings (tooltip, next button text)---  * @cachedir@ - the cache subdirectory.  We intialise this by creating a cache---    directory for images which will be generated from the results---  * @gvRef@ - see above-graphvizGui :: (GraphvizShow f d) => (Window a) -> String -> GraphvizGuiRef st d f -> GvIO st f d-graphvizGui f cachedir gvRef = do-  initGvSt <- readIORef gvRef-  -- widgets-  p <- panel f [ fullRepaintOnResize := False ]-  split <- splitterWindow p []-  (dtBitmap,sw) <- scrolledBitmap split -  rchoice  <- singleListBox split [tooltip := gvtip initGvSt]-  -- set handlers-  let openFn   = openImage sw dtBitmap -  -- pack it all together-  let lay = fill $ container p $ margin 1 $ fill $ -            vsplit split 5 200 (widget rchoice) (widget sw) -  set p [ on closing := closeImage dtBitmap ]-  -------------------------------------------------  -- create an updater function-  -------------------------------------------------  let withoutSelector job =-        bracket ( swap rchoice (on select) (return ()) )-                ( \fn -> set rchoice [ on select := fn ] )-                ( const job )-      -- the selector calls onUpdate which calls the selector-      -- indirectly by setting the selection-  let onUpdate = withoutSelector $ do-        gvSt <- readIORef gvRef-        let orders = gvorders gvSt-        initCacheDir cachedir-        Monad.when (GvoItems `elem` orders) $-          set rchoice [ items := gvlabels gvSt ]-        Monad.when (GvoSel `elem` orders) $-          set rchoice [ selection := gvsel gvSt ]-        modifyIORef gvRef (\x -> x { gvorders = []})-        createAndOpenImage cachedir p gvRef openFn-  -------------------------------------------------  -- enable the tree selector-  -- FIXME: not sure that this is correct-  -------------------------------------------------  let selectAndShow = do-        -- putStrLn "selectAndShow called" -        sel  <- get rchoice selection-        -- note: do not use setGvSel (infinite loop)-        modifyIORef gvRef (\x -> x { gvsel = sel })-        -- call the handler if there is one -        gvSt <- readIORef gvRef-        case (gvhandler gvSt) of -          Nothing -> return ()-          Just h  -> h gvSt-        -- now do the update-        onUpdate-  -------------------------------------------------  set rchoice [ on select := selectAndShow ]-  -- call the updater function for the first time-  setGvSel gvRef 1-  onUpdate -  -- return the layout, the gvRef, and an updater function-  -- The gvRef is to make it easier for users to muck around with the-  -- state of the gui.  Here, it's trivial, but when people combine guis-  -- together, it might be easier to keep track of when returned-  return (lay, gvRef, onUpdate)---- ---------------------------------------------------------------------- --- Bitmap stuff--- ---------------------------------------------------------------------- ---- | Bitmap with a scrollbar-scrolledBitmap :: Window a -> IO(VarBitmap, ScrolledWindow ())-scrolledBitmap p = do-  dtBitmap <- variable [value := Nothing]-  sw       <- scrolledWindow p [scrollRate := sz 10 10, bgcolor := white,-                                on paint := onPaint dtBitmap,-                                fullRepaintOnResize := False ]       -  return (dtBitmap, sw)--type OpenImageFn = FilePath -> IO ()-type VarBitmap   = Var (Maybe (Bitmap ())) --openImage :: Window a -> VarBitmap -> OpenImageFn-openImage sw vbitmap fname = do -    -- load the new bitmap-    bm <- bitmapCreateFromFile fname  -- can fail with exception-    closeImage vbitmap-    set vbitmap [value := Just bm]-    -- reset the scrollbars -    bmsize <- get bm size -    set sw [virtualSize := bmsize]-    repaint sw-      `catch` \_ -> repaint sw--closeImage :: VarBitmap -> IO ()-closeImage vbitmap = do -    mbBitmap <- swap vbitmap value Nothing-    case mbBitmap of-        Nothing -> return ()-        Just bm -> objectDelete bm--onPaint :: VarBitmap -> DC a -> b -> IO ()-onPaint vbitmap dc _ = do -    mbBitmap <- get vbitmap value-    case mbBitmap of-      Nothing -> return () -      Just bm -> do dcClear dc-                    drawBitmap dc bm pointZero False []---- | 'createAndOpenImage' attempts to draw an image (or retrieve it from cache)--- and opens it if we succeed.  Otherwise, it does nothing at all; the creation--- function will display an error message if it fails.-createAndOpenImage :: (GraphvizShow f b) => -  FilePath -> Window a -> GraphvizGuiRef st b f -> OpenImageFn -> IO ()-createAndOpenImage cachedir f gvref openFn = do -  let errormsg g = "The file " ++ g ++ " was not created!\n"-                   ++ "Is graphviz installed?"-  gvStatus <- createImage cachedir f gvref-  case gvStatus of-    GvCreated graphic ->-      do exists <- doesFileExist graphic-         if exists-            then openFn graphic-            else errorDialog f "" (errormsg graphic)-    GvError err -> errorDialog f "" err-    GvNoSuchItem _ -> return ()-    GvCached    -> return ()---- | Creates a graphical visualisation for anything which can be displayed---   by graphviz.-createImage :: (GraphvizShow f b)-            => FilePath            -- ^ cache directory-            -> Window a            -- ^ parent window-            -> GraphvizGuiRef st b f  -- ^ stuff to display-            -> IO GraphvizStatus-createImage cachedir f gvref = do-  gvSt <- readIORef gvref-  -- putStrLn $ "creating image via graphviz"-  let drawables = gvitems  gvSt-      sel       = gvsel    gvSt-      config    = gvparams gvSt-  dotFile <- createDotPath cachedir (show sel)-  graphicFile <-  createImagePath cachedir (show sel)-  let create x = do toGraphviz config x dotFile graphicFile-                    return . GvCreated $ graphicFile-      handler err = do errorDialog f "Error calling graphviz" (show err) -                       return . GvError . show $ err-  exists <- doesFileExist graphicFile-  -- we only call graphviz if the image is not in the cache-  if exists-     then return (GvCreated graphicFile)-     else case Map.lookup sel drawables of-            Nothing -> return . GvNoSuchItem $ sel-            Just it -> create it `catch` handler---- | Directory to dump image files in so that we can avoid regenerating them.---   If the directory already exists, we can just delete all the files in it.-initCacheDir :: String -> IO()-initCacheDir cachesubdir = do -  mainCacheDir <- gv_CACHEDIR-  cmainExists  <- doesDirectoryExist mainCacheDir -  Monad.when (not cmainExists) $ createDirectory mainCacheDir -  -- -  let cachedir = mainCacheDir </> cachesubdir-  cExists    <- doesDirectoryExist cachedir-  if (cExists)-    then do let notdot x = (x /= "." && x /= "..")-            contents <- getDirectoryContents cachedir-            olddir <- getCurrentDirectory-            setCurrentDirectory cachedir-            mapM removeFile $ filter notdot contents-            setCurrentDirectory olddir-            return ()-    else createDirectory cachedir---- ------------------------------------------------------------------------- Miscellaneous--- -------------------------------------------------------------------------- | Save the given string to a file, if the user selets one via the file save---   dialog. Otherwise, don't do anything.-maybeSaveAsFile :: (Window a) -> String -> IO ()-maybeSaveAsFile f msg =- do let filetypes = [("Any file",["*","*.*"])]-    fsel <- fileSaveDialog f False True "Save to" filetypes "" ""-    case fsel of-      Nothing   -> return ()-      Just file -> writeFile file msg---- | A message panel for use by the Results gui panels.-messageGui :: (Window a) -> String -> IO Layout -messageGui f msg = do -  p <- panel f []-  -- sw <- scrolledWindow p [scrollRate := sz 10 10 ]-  t  <- textCtrl p [ text := msg, enabled := False ]-  return (fill $ container p $ column 1 $ [ fill $ widget t ]) --gv_CACHEDIR :: IO String-gv_CACHEDIR = do-  home <- getHomeDirectory-  return $ home </> ".gvcache"--createImagePath :: String -> String -> IO String-createImagePath subdir name = do-  cdir <- gv_CACHEDIR-  return $ cdir </> subdir </> name <.> "png"--createDotPath :: String -> String -> IO String-createDotPath subdir name = do -  cdir <- gv_CACHEDIR-  return $ cdir </> subdir </> name <.> "dot"
+ src/NLP/GenI/LexicalSelection.hs view
@@ -0,0 +1,425 @@+-- GenI surface realiser+-- Copyright (C) 2005 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.++-- | This module performs the core of lexical selection and anchoring.+{-# LANGUAGE OverloadedStrings #-}+module NLP.GenI.LexicalSelection+where++import Control.Applicative ( (<$>) )+import Control.Arrow ((***))+import Control.Monad.Maybe+import Control.Monad.Writer+import Data.Function ( on )+import Data.List+import qualified Data.Map as Map+import Data.Maybe (catMaybes, fromMaybe, isJust, isNothing)+import Data.Tree (Tree(Node))+import qualified Data.Text as T+import Data.Text ( Text )++import Data.FullList hiding ( head, tail, (++) )+import qualified Data.FullList as FL++import NLP.GenI.FeatureStructure (Flist, AvPair(..), unifyFeat)+import NLP.GenI.General+    ( filterTree, repAllNode, histogram, geniBug, repNodeByNode,+    )+import NLP.GenI.GeniVal( unify, GeniVal(gConstraints), isConst, Subst, replace, finaliseVars )+import NLP.GenI.LexicalSelection.Types+import NLP.GenI.Lexicon ( LexEntry(..), Lexicon, )+import NLP.GenI.Semantics ( subsumeSem, unifySem, Sem )+import NLP.GenI.Tag ( TagElem(..), idname )+import NLP.GenI.TreeSchema ( Ttree(..), SchemaTree, SchemaNode, Macros+                           , crushTreeGNode+                           , setAnchor, setLexeme, tree+                           , GNode(..), GType(..)+                           )+import NLP.GenI.Warning++-- ----------------------------------------------------------------------+-- * Lexical selection algorithms+-- ----------------------------------------------------------------------++-- | See 'NLP.GenI.Configuration' if you want to use GenI with a custom+--   lexical selection function.+type LexicalSelector = Macros -> Lexicon -> Sem -> IO LexicalSelection++-- | The result of the lexical selection process+data LexicalSelection = LexicalSelection+      { -- | the main result: a set of elementary trees (ie. anchored trees)+        lsAnchored   :: [TagElem]+        -- | if available, lexical entries that were used to produce anchored+        --   trees (useful for identifying anchoring failure)+      , lsLexEntries :: [LexEntry]+        -- | HINT: use 'Data.Monoid.mempty' to initialise to empty+      , lsWarnings   :: GeniWarnings+      }++-- | Performs standard GenI lexical selection as described in+--   <http://projects.haskell.org/GenI/manual/lexical-selection.html>+--+--   This is just 'defaultLexicalSelection' lifted into IO+defaultLexicalSelector :: Macros -> Lexicon -> Sem -> IO LexicalSelection+defaultLexicalSelector g l t = return (defaultLexicalSelection g l t)++-- | Helper for 'defaultLexicalSelector'+--   (Standard GenI lexical selection is actually pure)+--+--   This is just 'defaultLexicalChoice' and 'defaultAnchoring'+defaultLexicalSelection :: Macros -> Lexicon -> Sem -> LexicalSelection+defaultLexicalSelection grammar lexicon tsem =+  defaultAnchoring grammar (defaultLexicalChoice lexicon tsem) tsem++-- | @missingLexEntries ts lexs@ returns any of the lexical candidates+--   @lexs@ that were apparently not anchored succesfully.+--+--   TODO: it does this by (wrongly) checking for each lexical item+--   to see if any of the anchored trees in @ts@ have identical+--   semantics to that lexical item.  The better way to do this would+--   be to throw a subsumption check on top of items reported missing,+--   because it's possible for the trees to add semantics through+--   unification.+missingLexEntries :: [TagElem] -> [LexEntry] -> [LexEntry]+missingLexEntries cands = filter treeless+ where+  treeless l = isNothing $ find (\t -> tsemantics t == isemantics l) cands++-- ----------------------------------------------------------------------+-- * Selecting candidate lemmas+-- ----------------------------------------------------------------------++-- | Select and returns the set of entries from the lexicon whose semantics+--   subsumes the input semantics.+defaultLexicalChoice :: Lexicon -> Sem -> [LexEntry]+defaultLexicalChoice slex tsem = chooseCandI tsem slex++-- | 'chooseCandI' @sem l@ attempts to unify the semantics of @l@ with @sem@+--   If this succeeds, we use return the result(s); if it fails, we reject+--   @l@ as a lexical selection candidate.+chooseCandI :: Sem -> [LexEntry] -> [LexEntry]+chooseCandI tsem cand =+  let replaceLex i (sem,sub) =+        (replace sub i) { isemantics = sem }+      --+      helper :: LexEntry -> [LexEntry]+      helper l = if null sem then [l]+                 else map (replaceLex l) psubsem+        where psubsem = sem `subsumeSem` tsem+              sem = isemantics l+      --+  in nub $ concatMap helper cand++-- | `mergeSynonyms' is a factorisation technique that uses+--   atomic disjunction to merge all synonyms into a single lexical+--   entry.  Two lexical entries are considered synonyms if their+--   semantics match and they point to the same tree families.+-- +--  FIXME: 2006-10-11 - note that this is no longer being used,+--  because it breaks the case where two lexical entries differ+--  only by their use of path equations.  Perhaps it's worthwhile+--  just to add a check that the path equations match exactly.+mergeSynonyms :: [LexEntry] -> [LexEntry]+mergeSynonyms lexEntry =+  let mergeFn l1 l2 = l1 { iword = (FL.++) (iword l1) (iword l2) }+      keyFn l = (ifamname l, isemantics l)+      synMap = foldr helper Map.empty lexEntry+        where helper x acc = Map.insertWith mergeFn (keyFn x) x acc+  in Map.elems synMap++-- --------------------------------------------------------------------+-- * Anchoring+-- --------------------------------------------------------------------++-- | The 'LexCombine' monad supports warnings during lexical selection+--   and also failure via Maybe+type LexCombine a = MaybeT (Writer [LexCombineError]) a++-- | Note an anchoring error+lexTell :: LexCombineError -> LexCombine ()+lexTell x = lift (tell [x])++-- | @defaultAnchoring schemata lex sem@  implements the later half of lexical+--   selection (tree anchoring and enrichement).  It assumes that @lex@ consists+--   just of the lexical items that have been selected, and tries to combine them+--   with the tree schemata.+--+--   This function may be useful if you are implementing your own lexical selection+--   functions, and you want GenI to take over after you've given it a @[LexEntry]@+defaultAnchoring :: Macros -> [LexEntry] -> Sem -> LexicalSelection+defaultAnchoring grammar lexCands tsem =+  LexicalSelection { lsAnchored   = cands+                   , lsLexEntries = lexCands+                   , lsWarnings   = mconcat [ lexWarnings, coanchorWarnings, errs ]+                   }+ where+  combinations  = map (combineList tsem grammar) lexCands+  cands         = concatMap snd combinations+  errs          = mkGeniWarnings . concat $ zipWith mkWarnings lexCands (map fst combinations)+  mkWarnings l  = map (LexWarning [l] . LexCombineOneSchemaFailed)+  coanchorWarnings = mkGeniWarnings $ do -- list monad+    l     <- lexCands+    let xs = filter (\p -> pfamily p == ifamname l) grammar+    (c,n) <- Map.toList . histogram $ concatMap (missingCoanchors l) xs+    return (LexWarning [l] (MissingCoanchors c n))+  lexWarnings = mkGeniWarnings $ case missingLexEntries cands lexCands of+                  [] -> []+                  xs -> [LexWarning xs LexCombineAllSchemataFailed]+++-- ----------------------------------------------------------------------+-- ** Combination+-- ----------------------------------------------------------------------++-- | Given a lexical item, looks up the tree families for that item, and+--   anchor the item to the trees.+combineList :: Sem -> Macros -> LexEntry+            -> ([LexCombineError],[TagElem]) -- ^ any warnings, plus the results+combineList tsem gram lexitem =+  case [ t | t <- gram, pfamily t == tn ] of+       []   -> ([FamilyNotFoundError tn],[])+       macs -> squish . swap . unzip $ map (\m -> runWriter . runMaybeT $ combineOne tsem lexitem m) macs+  where+   tn = ifamname lexitem+   swap (x,y) = (y,x)+   squish = (compressLexCombineErrors . concat) *** (concat . catMaybes)++-- | Combine a single tree with its lexical item to form a bonafide TagElem.+--   This process can fail, however, because of filtering or enrichement+combineOne :: Sem -> LexEntry -> SchemaTree -> LexCombine [TagElem]+combineOne tsem lexRaw eRaw = -- Maybe monad+ -- trace ("\n" ++ (show wt)) $+ do let l1 = finaliseVars "-l" lexRaw+        e1 = finaliseVars "-t" eRaw+    (l,e) <- unifyParamsWithWarning (l1,e1)+             >>= unifyInterfaceUsing iinterface+             >>= unifyInterfaceUsing ifilters -- filtering+             >>= enrichWithWarning -- enrichment+    tree2 <- case crushTreeGNode (tree e) of+               Nothing -> do lexTell (SchemaError [pidname e]+                                 (StringError "Could not flatten disjunction"))+                             fail ""+               Just x  -> return x+    let name = T.intercalate ":" $ filter (not . T.null)+                 [ FL.head (iword l) , pfamily e , pidname e ]+        template = TE+              { idname = name+              , ttreename = pfamily e+              , tidnum    = -1 -- provisional id+              , ttype = ptype e+              , ttree = setOrigin name . setLemAnchors . setAnchor (iword l) $ tree2+              , tsemantics  = []+              , tsempols    = isempols l+              , tpolarities = Map.empty+              , tinterface  = pinterface e+              , ttrace      = ptrace e+              }+    semUnifications <- case unifySem (isemantics l) (fromMaybe [] $ psemantics e) of+                         [] -> do lexTell (SchemaError [pidname e] (StringError "could not unify lemma and schema semantics"))+                                  fail ""+                         xs -> return xs+    return $ concatMap (finaliseSemantics template) semUnifications+ where+  croak t msg = do+      lexTell (SchemaError [pidname t] (StringError msg))+      fail ""+  finaliseSemantics template (sem,sub) =+    do (sem2,sub2) <- sem `subsumeSem` replace sub tsem+       return $ replace sub2 $ template { tsemantics = sem2 }+  unifyParamsWithWarning (l,t) =+   -- trace ("unify params " ++ wt) $+   let lp = iparams l+       tp = params t+   in if length lp /= length tp+      then croak t "Parameter length mismatch"+      else case unify lp tp of+             Nothing -> croak t "Parameter unification error"+             Just (ps2, subst) -> return (replace subst l, t2)+                                  where t2 = (replace subst t) { params = ps2 }+  unifyInterfaceUsing ifn (l,e) =+    -- trace ("unify interface" ++ wt) $+    case unifyFeat (ifn l) (pinterface e) of+    Nothing             -> croak e "Interface unification error"+    Just (int2, fsubst) -> return (replace fsubst l, e2)+                           where e2 = (replace fsubst e) { pinterface = int2 }+  --+  enrichWithWarning (l,e) =+    -- trace ("enrich" ++ wt) $+    do e2 <- enrich l e+       return (l,e2)++-- ----------------------------------------------------------------------+-- ** Enrichment+-- ----------------------------------------------------------------------++-- | See <http://projects.haskell.org/manual/lexical-selection>+--   on enrichement+enrich :: LexEntry -> SchemaTree -> LexCombine SchemaTree+enrich l t =+ do -- separate into interface/anchor/named+    (intE, namedE) <- lift $ lexEquations l+    -- enrich the interface and everything else+    t2 <- foldM enrichInterface t intE+    -- enrich everything else+    foldM enrichBy t2 namedE+ where+  enrichInterface tx en =+    case unifyFeat [en] (pinterface tx) of+      Nothing -> lexTell (ifaceEnrichErr en) >> fail ""+      Just (i2, isubs) -> return $ (replace isubs tx) { pinterface = i2 }+  ifaceEnrichErr (AvPair loc _) =+       SchemaError [pidname t] (EnrichError (PeqInterface loc))++-- *** 'enrich' helpers++-- | Helper for 'enrich' (enrich by single path equation)+enrichBy :: SchemaTree+         -> PathEqPair+         -> LexCombine SchemaTree+enrichBy t eq@(eqLhs, _) =+  case maybeEnrichBy t eq of+    Nothing -> lexTell enrichErr >> return t+    Just (t2,_) -> return t2+ where+  enrichErr = SchemaError [pidname t] (EnrichError (PeqJust eqLhs))++-- | Helper for 'enrichBy'+maybeEnrichBy :: SchemaTree+              -> PathEqPair+              -> Maybe (SchemaTree, Subst)+maybeEnrichBy t (eqLhs, eqVal) = do+  node <- seekCoanchor eqLhs t+  case eqLhs of+    PeqFeat _ eqTop eqAtt -> do+      let (get, set) = case eqTop of+                         Top     -> (gup,   \n x -> n { gup = x })+                         Bottom  -> (gdown, \n x -> n { gdown = x})+      (fs, sub) <- enrichFeat (AvPair eqAtt eqVal) (get node)+      let t2 = fixNode (set node fs) (replace sub t)+      return (t2, sub)+    PeqLex _ -> do+       vs <- gConstraints eqVal+       let node2 = node { glexeme = FL.fromFL vs }+           t2    = fixNode node2 t+       return (t2, Map.empty)+ where+  fixNode n mt = mt { tree = repNodeByNode (matchNodeName eqLhs) n (tree mt) }++-- | @enrichFeat av fs@ attempts to unify @av@ with @fs@+--+--   Note here that @fs@ is an @Flist [GeniVal]@ rather than the usual+--   @Flist GeniVal@ you may expect.  This is because it comes from+--   'SchemaTree' which allows non-atomic disjunctions of @GeniVal@+--   which have to be flatten down to at most atomic disjunctions once+--   lexical selection is complete.+enrichFeat :: AvPair GeniVal -> Flist [GeniVal] -> Maybe (Flist [GeniVal], Subst)+enrichFeat (AvPair a v) fs =+  case span (\x -> avAtt x < a) fs of+    (before,here:after) | avMatch here ->+      do let (AvPair _ fv) = here+         (v2,sub) <- unify fv (replicate (length fv) v)+         let av2 = AvPair a v2+             fs2 = replace sub before ++ (av2 : replace sub after)+         return (fs2, sub)+    (before,after) ->+      let av2 = AvPair a [v]+          fs2 = before ++ (av2 : after) in  Just (fs2, Map.empty)+  where+   avMatch (AvPair fa _) = fa == a++-- | @missingCoanchors l t@ returns the list of coanchor node names from @l@+--   that were not found in @t@+missingCoanchors :: LexEntry -> SchemaTree -> [Text]+missingCoanchors lexEntry t =+   [ name eqLhs | eqLhs <- nubBy ((==) `on` name) equations, missing eqLhs ]+ where+   equations = map fst . snd . fst . runWriter $ lexEquations lexEntry+   name (PeqFeat n _ _) = n+   name (PeqLex  n)     = n+   missing eqLhs = isNothing (seekCoanchor eqLhs t)++-- | Split a lex entry's path equations into interface enrichement equations+--   or (co-)anchor modifiers+lexEquations :: LexEntry -> Writer [LexCombineError] ([AvPair GeniVal],[PathEqPair])+lexEquations =+  fmap myPartition . mapM parseAv . iequations+  where+   myPartition xs = ( [ AvPair a v | (PeqInterface a, v) <- xs ]+                    , [ (n,v)      | (PeqJust n, v)      <- xs ] )+   parseAv (AvPair a v) = fmap (\a2 -> (a2,v)) (parsePathEq a)++-- | @seekCoanchor lhs t@ returns @Just node@ if @t@ contains exactly one+--   node that can be identified by @lhs@, @Nothing@ if it contains none.+--+--   It crashes if there is more than one such node, because this should+--   have been caught earlier by GenI.+seekCoanchor :: NodePathEqLhs -> SchemaTree -> Maybe SchemaNode+seekCoanchor eqLhs t =+   case filterTree (matchNodeName eqLhs) (tree t) of+        [a] -> Just a+        []  -> Nothing+        _   -> geniBug . T.unpack . T.intercalate "\n" $+            [ "NLP.GenI.LexicalSelection.seekCoanchor:"+            , "Did not expect to see a tree with multiple matches in enrichBy."+            , "Tree: "   `T.append` pidname t+            , "Family: " `T.append` pfamily t+            , "Matching on: " `T.append` showPathEqLhs (PeqJust eqLhs)+            ]++-- | @matchNodeName lhs n@ is @True@ if the @lhs@ refers to the node @n@+matchNodeName :: NodePathEqLhs -> SchemaNode -> Bool+matchNodeName (PeqFeat n _ _) = matchNodeNameHelper n+matchNodeName (PeqLex n)      = matchNodeNameHelper n++-- | @matchNodeNameHelper@ recognises “anchor“ by convention; otherwise,+--   it does a name match+matchNodeNameHelper :: Text -> SchemaNode -> Bool+matchNodeNameHelper "anchor" = ganchor+matchNodeNameHelper n        = (== n) . gnname++-- ----------------------------------------------------------------------+-- ** Lemanchor mechanism+-- ----------------------------------------------------------------------++-- | The lemanchor mechanism is described in+--   <http://projects.haskell.org/manual/lexical-selection>+setLemAnchors :: Tree (GNode GeniVal) -> Tree (GNode GeniVal)+setLemAnchors t =+    repAllNode fn filt t+  where+    filt (Node a []) = gtype a == Subs && (isJust. lemAnchor) a+    filt _           = False+    fn (Node x k) = setLexeme (lemAnchorMaybeFake x) $+        Node (x { gtype = Other, gaconstr = False }) k+    --+    lemAnchorMaybeFake :: GNode GeniVal -> [Text]+    lemAnchorMaybeFake n =+        fromMaybe ["ERR_UNSET_LEMMANCHOR"] (lemAnchor n)+    lemAnchor :: GNode GeniVal -> Maybe [Text]+    lemAnchor n =+        case [ v | AvPair a v <- gup n, a == _lemanchor ] of+            [l] | isConst l -> fromFL <$> gConstraints l+            _               -> Nothing++-- | The name of the lemanchor attribute (by convention; see source)+_lemanchor :: Text+_lemanchor = "lemanchor"++-- | @setOrigin n t@ marks the nodes in @t@ as having come from+--   a tree named @n@+setOrigin :: Text -> Tree (GNode v) -> Tree (GNode v)+setOrigin t = fmap (\g -> g { gorigin = t })
+ src/NLP/GenI/LexicalSelection/Types.hs view
@@ -0,0 +1,149 @@+-- GenI surface realiser+-- Copyright (C) 2012 Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.++{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE OverloadedStrings #-}+module NLP.GenI.LexicalSelection.Types where++import Control.Monad.Writer+import Data.List+import Data.Poset+import Data.Text ( Text )+import qualified Data.Map as Map+import qualified Data.Text as T++import NLP.GenI.GeniVal+import NLP.GenI.Pretty++-- | Left hand side of a path equation+data PathEqLhs = PeqInterface   Text+               | PeqJust        NodePathEqLhs+               | PeqUnknown     Text+  deriving (Eq, Ord)++-- ----------------------------------------------------------------------+-- * Path equations+-- ----------------------------------------------------------------------++-- | Path equations can either hit a feature or a node's lexeme attribute+data NodePathEqLhs = PeqFeat Text TopBottom Text+                   | PeqLex  Text+  deriving (Eq, Ord)++data TopBottom = Top | Bottom+  deriving (Eq, Ord)++type PathEqPair = (NodePathEqLhs, GeniVal)++-- | Parse a path equation using the GenI conventions+--   This always succeeds, but can return @Just warning@+--   if anything anomalous comes up+--   FIXME : make more efficient+parsePathEq :: Text -> Writer [LexCombineError] PathEqLhs+parsePathEq e =+    case T.splitOn "." e of+        (n:"top":r)     -> return (node n Top    r)+        (n:"bot":r)     -> return (node n Bottom r)+        [n,"lex"]       -> return (PeqJust (PeqLex n))+        ("top":r)       -> return (node "anchor" Top r)+        ("bot":r)       -> return (node "anchor" Bottom r)+        ("anchor":r)    -> return (node "anchor" Bottom r)+        ("interface":r) -> return (PeqInterface  (rejoin r))+        ("anc":r)       -> parsePathEq $ rejoin ("anchor":r)+        (n:r@(_:_))     -> tell [BoringError (tMsg n)] >> return (node n Top r)+        _               -> tell [BoringError iMsg    ] >> return (PeqUnknown e)+  where+    node n tb r = PeqJust $ PeqFeat n tb (rejoin r)+    rejoin = T.intercalate "."+    tMsg n = T.unwords+        [ "Interpreting path equation"+        , e+        , "as applying to top of"+        , n `T.snoc` '.'+        ]+    iMsg = "Could not interpret path equation" <+> e++showPathEqLhs :: PathEqLhs -> Text+showPathEqLhs p =+    case p of+        PeqJust (PeqFeat n tb att) -> squish [ n, fromTb tb, att ]+        PeqJust (PeqLex  n)        -> squish [ n, "lex" ]+        PeqInterface att           -> squish [ "interface", att ]+        PeqUnknown e               -> e+  where+    fromTb Top    = "top"+    fromTb Bottom = "bot"+    squish = T.intercalate "."++-- ----------------------------------------------------------------------+-- * Warnings+-- ----------------------------------------------------------------------++data LexCombineError =+       BoringError Text+     | FamilyNotFoundError Text+     | SchemaError [Text] LexCombineError2+ deriving Eq++data LexCombineError2 = EnrichError PathEqLhs+                      | StringError Text+ deriving (Eq, Ord)++instance Poset LexCombineError where+ leq (BoringError _) _                                 = True+ leq (SchemaError _ e1) (SchemaError _ e2)             = leq e1 e2+ leq (FamilyNotFoundError x1) (FamilyNotFoundError x2) = leq x1 x2+ leq (FamilyNotFoundError _)  (SchemaError _ _)        = True+ leq _ _ = False++instance Poset LexCombineError2 where+ leq (EnrichError e1) (EnrichError e2)  = leq e1 e2+ leq (EnrichError _ ) (StringError _ )  = True+ leq (StringError s1) (StringError s2)  = leq s1 s2+ leq _ _ = False++instance Poset PathEqLhs where+ leq l1 l2 = leq (showPathEqLhs l1) (showPathEqLhs l2)++instance Poset Text where+    leq l1 l2 = leq (T.unpack l1) (T.unpack l2)++instance Pretty LexCombineError where+    pretty e =+        body <+> suffix+      where+        (body, suffix) = showLexCombineError e++showLexCombineError :: LexCombineError -> (Text, Text)+showLexCombineError (SchemaError xs x) = (pretty  x, prettyCount (const "") "trees" ((), length xs))+showLexCombineError (BoringError s)    = (s, "")+showLexCombineError (FamilyNotFoundError f) = ("Family" <+> f <+> "not found in tree schema file", "")++instance Pretty LexCombineError2 where+    pretty (EnrichError p) =+        "Some trees discarded due to enrichment error on" <+> showPathEqLhs p+    pretty (StringError s) = s++compressLexCombineErrors :: [LexCombineError] -> [LexCombineError]+compressLexCombineErrors errs = schema2 ++ normal+ where+  isSchema (SchemaError _ _) = True+  isSchema _ = False+  (schema, normal) = partition isSchema errs+  schema2 = map (uncurry (flip SchemaError))+          . Map.toList+          $ Map.fromListWith (++) [ (l,ts) | SchemaError ts l <- schema ]
+ src/NLP/GenI/Lexicon.hs view
@@ -0,0 +1,27 @@+-- GenI surface realiser+-- Copyright (C) 2005-2009 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.++module NLP.GenI.Lexicon (+   Lexicon,+   -- anything but the constructor+   LexEntry, mkLexEntry, mkFullLexEntry,+   iword , ifamname, iparams, iinterface , ifilters, iequations, isemantics, isempols,+   -- * Converting between lexical/normal semantics+   PolValue, fromLexSem, fromLexLiteral,+) where++import NLP.GenI.Lexicon.Internal
+ src/NLP/GenI/Lexicon/Internal.hs view
@@ -0,0 +1,203 @@+-- GenI surface realiser+-- Copyright (C) 2005-2009 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.++{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE OverloadedStrings #-}+module NLP.GenI.Lexicon.Internal where++-- import Debug.Trace -- for test stuff+import Data.Binary+import Data.FullList+import Data.Function+import Data.List ( sortBy )+import Data.Generics (Data)+import Data.Text ( Text )+import Data.Typeable (Typeable)+import qualified Data.Text as T++import NLP.GenI.FeatureStructure+import NLP.GenI.GeniShow+import NLP.GenI.GeniVal+import NLP.GenI.Pretty+import NLP.GenI.Semantics+import NLP.GenI.Polarity.Types (SemPols)++import Control.DeepSeq++--instance Show (IO()) where+--  show _ = ""++type Lexicon = [LexEntry]+data LexEntry = LexEntry+    { -- normally just a singleton, useful for merging synonyms+      iword       :: FullList Text+    , ifamname    :: Text+    , iparams     :: [GeniVal]+    , iinterface  :: Flist GeniVal+    , ifilters    :: Flist GeniVal+    , iequations  :: Flist GeniVal+    , isemantics  :: Sem+    , isempols    :: [SemPols] }+  deriving (Eq, Data, Typeable)++-- | See also 'mkFullLexEntry'+--   This version comes with some sensible defaults.+mkLexEntry :: FullList Text   -- ^ word+            -> Text            -- ^ family name+            -> [GeniVal]       -- ^ parameters list (deprecated)+            -> Flist GeniVal   -- ^ interface (use instead of params)+            -> Flist GeniVal   -- ^ filters+            -> Flist GeniVal   -- ^ equations+            -> Sem             -- ^ semantics+            -> LexEntry+mkLexEntry word famname params interface filters equations sem =+  mkFullLexEntry word famname params interface filters equations+      sem (map noSemPols sem)+  where+   noSemPols l = replicate (length (lArgs l)) 0++-- | Variant of 'mkLexEntry' but with more control+mkFullLexEntry :: FullList Text   -- ^ word+                -> Text            -- ^ family name+                -> [GeniVal]       -- ^ parameters list (deprecated)+                -> Flist GeniVal   -- ^ interface (use instead of params)+                -> Flist GeniVal   -- ^ filters+                -> Flist GeniVal   -- ^ equations+                -> Sem             -- ^ semantics+                -> [SemPols]       -- ^ semantic polarities+                -> LexEntry+mkFullLexEntry word famname params interface filters equations sem sempols =+    LexEntry+        (sortNub word)+        famname+        params+        (sortFlist interface)+        (sortFlist filters)+        (sortFlist equations)+        sem2+        sempols2+  where+     (sem2, sempols2) = unzip $ sortBy (compareOnLiteral `on` fst) (zip sem sempols)++instance DescendGeniVal LexEntry where+  descendGeniVal s i =+    i { iinterface  = descendGeniVal s (iinterface i)+      , iequations  = descendGeniVal s (iequations i)+      , isemantics  = descendGeniVal s (isemantics i)+      , iparams = descendGeniVal s (iparams i) }++instance Collectable LexEntry where+  collect l = (collect $ iinterface l) . (collect $ iparams l) .+              (collect $ ifilters l) . (collect $ iequations l) .+              (collect $ isemantics l)++-- ----------------------------------------------------------------------+-- lexicon semantics+-- ----------------------------------------------------------------------++-- | An annotated GeniVal. This is for a rather old, obscure+--   variant on the polarity filtering optimisation. To account+--   for zero literal semantics, we annotate each value in the+--   semantics with a positive/negative marker.  These markers+--   are then counted up to determine with we need to insert+--   more literals into the semantics or not.  See the manual+--   on polarity filtering for more details+type PolValue = (GeniVal, Int)++fromLexSem :: [Literal PolValue] -> (Sem, [SemPols])+fromLexSem = unzip . map fromLexLiteral++-- | Note that by convention we ignore the polarity associated+--   with the predicate itself+fromLexLiteral :: Literal PolValue -> (Literal GeniVal, SemPols)+fromLexLiteral (Literal h pr vs) =+    (lit, pols)+  where+    lit  = Literal (fst h) (fst pr) (map fst vs)+    pols = snd h : map snd vs++-- ----------------------------------------------------------------------+-- converting to text+-- ----------------------------------------------------------------------++-- TODO: does not support semantic polarities yet+instance GeniShow LexEntry where+    geniShowText l = T.intercalate "\n"+        [ T.unwords+              [ geniShowText . mkGConst $ iword l+              , ifamname l+              , paramT+              ]+        , geniKeyword "equations" $ geniShowText (iequations l)+        , geniKeyword "filters"   $ geniShowText (ifilters l)+        , geniKeyword "semantics" $ geniShowText (isemantics l)+        ]+      where +        paramT = parens . T.unwords . concat $+            [ map geniShowText (iparams l)+            , ["!"]+            , map geniShowText (iinterface l)+            ]++instance GeniShow [LexEntry] where+    geniShowText = T.intercalate "\n\n" . map geniShowText++instance Pretty LexEntry where+    pretty = geniShowText++-- ----------------------------------------------------------------------+--+-- ----------------------------------------------------------------------++{-!+deriving instance Binary LexEntry+deriving instance NFData LexEntry+!-}++-- GENERATED START++ +instance Binary LexEntry where+        put (LexEntry x1 x2 x3 x4 x5 x6 x7 x8)+          = do put x1+               put x2+               put x3+               put x4+               put x5+               put x6+               put x7+               put x8+        get+          = do x1 <- get+               x2 <- get+               x3 <- get+               x4 <- get+               x5 <- get+               x6 <- get+               x7 <- get+               x8 <- get+               return (LexEntry x1 x2 x3 x4 x5 x6 x7 x8)++ +instance NFData LexEntry where+        rnf (LexEntry x1 x2 x3 x4 x5 x6 x7 x8)+          = rnf x1 `seq`+              rnf x2 `seq`+                rnf x3 `seq`+                  rnf x4 `seq` rnf x5 `seq` rnf x6 `seq` rnf x7 `seq` rnf x8 `seq` ()+-- GENERATED STOP
+ src/NLP/GenI/Main.hs view
@@ -0,0 +1,58 @@+-- GenI surface realiser+-- Copyright (C) 2005 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.++{-# LANGUAGE CPP #-}+module NLP.GenI.Main where++import Control.Applicative ((<$>))+import Data.IORef(newIORef)+import Data.Typeable( Typeable )+import Data.Version ( showVersion )+import System.Environment(getArgs, getProgName)++import Paths_GenI ( version )++import NLP.GenI.Console(consoleGeni)+import NLP.GenI.Configuration (treatArgs, optionsForStandardGenI, processInstructions,+                               usage, optionsSections, Params,+                               hasFlagP, DisableGuiFlg(..),+                               HelpFlg(..), VersionFlg(..),+                               readGlobalConfig, setLoggers+                              )+import NLP.GenI.Configuration(setFlagP)+import NLP.GenI ( ProgState(..), emptyProgState )++main :: IO ()+main = do+  args  <- getArgs+  confArgs <- forceGuiFlag <$> (processInstructions =<< treatArgs optionsForStandardGenI args)+  mainWithState (emptyProgState confArgs)++mainWithState :: ProgState -> IO ()+mainWithState pst = do+  pname <- getProgName+  maybe (return ()) setLoggers =<< readGlobalConfig+  pstRef <- newIORef pst+  let has :: (Typeable f, Typeable x) => (x -> f) -> Bool+      has = flip hasFlagP (pa pst)+  case () of+   _ | has HelpFlg               -> putStrLn (usage optionsSections pname)+     | has VersionFlg            -> putStrLn (pname ++ " " ++ showVersion version)+     | otherwise                 -> consoleGeni pstRef++forceGuiFlag :: Params -> Params+forceGuiFlag = setFlagP DisableGuiFlg ()
+ src/NLP/GenI/Morphology.hs view
@@ -0,0 +1,218 @@+-- GenI surface realiser+-- Copyright (C) 2005 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.++{-|+This module handles mostly everything to do with morphology in Geni.+There are two basic tasks: morphological input and output.+GenI farms out morphology to whatever third party program you+specify on the command line.  Note that a simple and stupid+``sillymorph'' realiser is provided either in the GenI repository+or on hackage.+-}++{-# LANGUAGE DeriveDataTypeable #-}+module NLP.GenI.Morphology+ (+ module NLP.GenI.Morphology.Types+ -- * Morphological predicates+ , readMorph, stripMorphSem, attachMorph, setMorphAnchor+ -- * Morphological realisation+ , inflectSentencesUsingCmd, sansMorph+ ) where++import Control.Concurrent (forkIO)+import Control.Exception (catch, bracket, evaluate, IOException)+import Data.Maybe (isNothing)+import Data.Text ( Text )+import Data.Tree+import Data.Typeable+import System.Exit+import System.IO+import System.Process+import Prelude hiding (catch)+import qualified Data.Map as Map+import qualified Data.Text as T++import System.Log.Logger+import Text.JSON+import Text.JSON.Pretty++import NLP.GenI.FeatureStructure+import NLP.GenI.GeniVal ( mkGAnon, GeniVal, replace )+import NLP.GenI.General+import NLP.GenI.Morphology.Types+import NLP.GenI.Pretty+import NLP.GenI.Semantics ( Literal(..), Sem )+import NLP.GenI.Tag+import NLP.GenI.TreeSchema ( GNode(..), GType(..) )++-- ----------------------------------------------------------------------+-- Morphological input+-- ----------------------------------------------------------------------++-- | Converts information from a morphological information file into GenI's+--   internal format.+readMorph :: [(Text,[AvPair GeniVal])] -> MorphInputFn+readMorph minfo lit =+    Map.lookup key fm+  where+    fm = Map.fromList minfo+    key = pretty (lPredicate lit)++-- | Filters away from an input semantics any literals whose realisation is+--   strictly morphological.  The first argument tells us helps identify the+--   morphological literals -- it associates literals with morphological stuff;+--   if it returns 'Nothing', then it is non-morphological+stripMorphSem :: MorphInputFn -> Sem -> Sem+stripMorphSem morphfn tsem = +  [ l | l <- tsem, (isNothing.morphfn) l ]++-- | 'attachMorph' @morphfn sem cands@ does the bulk of the morphological+--   input processing.  We use @morphfn@ to determine which literals in+--   @sem@ contain morphological information and what information they contain.+--   Then we attach this morphological information to the relevant trees in+--   @cand@.  A tree is considered relevant w.r.t to a morphological+--   literal if its semantics contains at least one literal whose first index+--   is the same as the first index of the morphological literal.+attachMorph :: MorphInputFn -> Sem -> [TagElem] -> [TagElem]+attachMorph morphfn sem cands = +  let -- relevance of a tree wrt to an index+      relTree i = not.null.relfilt.tsemantics+        where relfilt = filter (relLit i)  +      relLit i l = case lArgs l of+                     []    -> False+                     (x:_) -> x == i+      -- perform the attachment for a tree if it is relevant+      attachHelper :: GeniVal -> Flist GeniVal -> TagElem -> TagElem+      attachHelper i mfs t = +        if relTree i t then attachMorphHelper mfs t else t +      -- perform all attachments for a literal+      attach :: Literal GeniVal -> [TagElem] -> [TagElem]+      attach l cs = +        case morphfn l of +          Nothing  -> cs+          Just mfs -> map (attachHelper i mfs) cs+        where i = case lArgs l of+                    []    -> mkGAnon+                    (x:_) -> x+  in foldr attach cands sem ++-- | Actually unify the morphological features into the anchor node+--+--   FIXME: we'll need to make sure this still works as promised +--   when we implement co-anchors.+attachMorphHelper :: Flist GeniVal -> TagElem -> TagElem+attachMorphHelper mfs te = +  let -- unification with anchor+      tt     = ttree te +      anchor = head $ filterTree fn tt+               where fn a = (ganchor a && gtype a == Lex)+  in case unifyFeat mfs (gup anchor) of+     Nothing -> error ("Morphological unification failure on " ++ T.unpack (idname te))+     Just (unf,subst) ->+      let -- perform replacements+          te2 = replace subst te +          tt2 = ttree te2+          -- replace the anchor with the unification results+          newgdown = replace subst (gdown anchor) +          newa = anchor { gup = unf, gdown = newgdown }+      in te2 { ttree = setMorphAnchor newa tt2 }++setMorphAnchor :: GNode GeniVal -> Tree (GNode GeniVal) -> Tree (GNode GeniVal)+setMorphAnchor n t =+  let filt (Node a _) = (gtype a == Lex && ganchor a)+      fn (Node _ l)   = Node n l+  in (head.fst) $ listRepNode fn filt [t]++-- ----------------------------------------------------------------------+-- Morphological realisation+-- ----------------------------------------------------------------------++-- | Extracts the lemmas from a list of uninflected sentences.  This is used+--   when the morphological generator is unavailable, doesn't work, etc.+sansMorph :: LemmaPlusSentence -> MorphOutput+sansMorph =+    MorphOutput [] . singleton . T.unwords . map lem+  where+    lem (LemmaPlus l _) = l++-- | Converts a list of uninflected sentences into inflected ones by calling+---  the third party software.+-- FIXME: this doesn't actually support lists-of-results per input+-- will need to work it out+-- HUH? What makes me say that?+inflectSentencesUsingCmd :: String -> [LemmaPlusSentence] -> IO [(LemmaPlusSentence,MorphOutput)]+inflectSentencesUsingCmd morphcmd sentences =+  doit `catch` \e -> let _ = e :: IOException in (fallback (show e))+ where+  hCloseSloppy h = hClose h `catch` \err -> let _ = err :: IOException in warningM logname (show err)+  doit = bracket+   (do debugM logname $ "Starting morph generator: " ++ morphcmd +       runInteractiveCommand morphcmd)+   (\(inh,outh,errh,_) -> do+      debugM logname $ "Closing output handles from morph generator"+      mapM hCloseSloppy [inh, outh, errh])+    $ \(toP,fromP,errP,pid) -> do+     debugM logname $ "Sending " ++ show (length sentences) ++ " sentences to morph generator"+     hPutStrLn toP . render . pp_value . showJSON $ sentences++     debugM logname $ "Closing input handle to morph generator"+     hClose toP+     -- see http://www.haskell.org/pipermail/haskell-cafe/2008-May/042994.html+     -- fork off a thread to pull on the stderr+     -- so if the process writes to stderr we do not block.+     -- NB. do the hGetContents synchronously, otherwise the outer+     -- bracket can exit before this thread has run, and hGetContents+     -- will fail.+     err <- hGetContents errP+     _ <- forkIO (evaluate (length err) >> warningM logname err)++     -- wait for all the output+     output <- hGetContents fromP+     _ <- evaluate (length output)++     -- wait for the program to terminate+     exitcode <- waitForProcess pid+     debugM logname $ "Morph command exited"+     -- on failure, throw the exit code as an exception+     if exitcode == ExitSuccess+        then case resultToEither (decode output) of+               Left jerr  -> fallback $ "Could not parse morphological generator output: " ++ jerr+               Right res -> do let lenResults   = length res+                                   lenSentences = length sentences+                               if lenResults == lenSentences+                                  then return $ zip sentences res+                                  else fallback $ "Morphological generator returned "+                                                  ++ show lenResults ++ " results for "+                                                  ++ show lenSentences ++ " inputs"+                            `catch` \e -> let _ = e :: IOException+                                          in  fallback ("Error calling morphological generator:\n" ++ show e)+        else fallback "Morph generator failed"+  fallback err = do+    errorM logname err+    return $ map (\x -> (x, sansMorph x)) sentences++-- ----------------------------------------------------------------------+-- odds and ends+-- ----------------------------------------------------------------------++singleton :: a -> [a]+singleton x = [x]++data MNAME = MNAME deriving Typeable+logname :: String+logname = mkLogname MNAME
− src/NLP/GenI/Morphology.lhs
@@ -1,233 +0,0 @@-% GenI surface realiser-% Copyright (C) 2005 Carlos Areces and Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.--\chapter{Morphology}-\label{cha:Morphology}--This module handles mostly everything to do with morphology in Geni.-There are two basic tasks: morphological input and output.-GenI farms out morphology to whatever third party program you-specify on the command line.  Note that a simple and stupid-``sillymorph'' realiser is provided either in the GenI repository-or on hackage.--\begin{code}-module NLP.GenI.Morphology- (- MorphFn- -- re-export- , LemmaPlus(..), LemmaPlusSentence- -- * Morphological predicates- , readMorph, stripMorphSem, attachMorph, setMorphAnchor- -- * Morphological realisation- , inflectSentencesUsingCmd, sansMorph- ) where-\end{code}--\ignore{-\begin{code}-import Data.Maybe (isNothing)-import Data.Tree-import qualified Data.Map as Map-import System.IO-import System.Process-import Text.JSON-import Text.JSON.Pretty--import NLP.GenI.Btypes-import NLP.GenI.General-import NLP.GenI.Tags-import NLP.GenI.Builder-\end{code}-}--\begin{code}-type MorphFn = Pred -> Maybe Flist-\end{code}--\section{Morphological input}--Morphological input means attaching morphological features on trees.  The-user specifies morphological input through the input semantics.  Our job-is to identify morphological predicates like \semexpr{plural(x)} and -apply features like \fs{\it num:pl} on the relevant trees.--\begin{code}--- | Converts information from a morphological information file into GenI's---   internal format.-readMorph :: [(String,[AvPair])] -> MorphFn-readMorph minfo pred_ = Map.lookup key fm-  where fm = Map.fromList minfo-        key = show $ snd3 pred_---- | Filters away from an input semantics any literals whose realisation is---   strictly morphological.  The first argument tells us helps identify the---   morphological literals -- it associates literals with morphological stuff;---   if it returns 'Nothing', then it is non-morphological-stripMorphSem :: MorphFn -> Sem -> Sem-stripMorphSem morphfn tsem = -  [ l | l <- tsem, (isNothing.morphfn) l ]---- | 'attachMorph' @morphfn sem cands@ does the bulk of the morphological---   input processing.  We use @morphfn@ to determine which literals in---   @sem@ contain morphological information and what information they contain.---   Then we attach this morphological information to the relevant trees in---   @cand@.  A tree is considered relevant w.r.t to a morphological---   literal if its semantics contains at least one literal whose first index---   is the same as the first index of the morphological literal.-attachMorph :: MorphFn -> Sem -> [TagElem] -> [TagElem]-attachMorph morphfn sem cands = -  let -- relevance of a tree wrt to an index-      relTree i = not.null.relfilt.tsemantics-        where relfilt = filter (relLit i)  -      relLit i l = if null args then False else (head args == i)-        where args = thd3 l-      -- perform the attachment for a tree if it is relevant-      attachHelper :: GeniVal -> Flist -> TagElem -> TagElem  -      attachHelper i mfs t = -        if relTree i t then attachMorphHelper mfs t else t -      -- perform all attachments for a literal-      attach :: Pred -> [TagElem] -> [TagElem]-      attach l cs = -        case morphfn l of -          Nothing  -> cs-          Just mfs -> map (attachHelper i mfs) cs-        where i = if null args then GAnon else head args-              args = thd3 l -  in foldr attach cands sem ---- | Actually unify the morphological features into the anchor node------   FIXME: we'll need to make sure this still works as promised ---   when we implement co-anchors.-attachMorphHelper :: Flist -> TagElem -> TagElem-attachMorphHelper mfs te = -  let -- unification with anchor-      tt     = ttree te -      anchor = head $ filterTree fn tt-               where fn a = (ganchor a && gtype a == Lex)-  in case unifyFeat mfs (gup anchor) of-     Nothing -> error ("Morphological unification failure on " ++ idname te)-     Just (unf,subst) ->-      let -- perform replacements-          te2 = replace subst te -          tt2 = ttree te2-          -- replace the anchor with the unification results-          newgdown = replace subst (gdown anchor) -          newa = anchor { gup = unf, gdown = newgdown }-      in te2 { ttree = setMorphAnchor newa tt2 }--setMorphAnchor :: GNode -> Tree GNode -> Tree GNode-setMorphAnchor n t =-  let filt (Node a _) = (gtype a == Lex && ganchor a)-      fn (Node _ l)   = Node n l-  in (head.fst) $ listRepNode fn filt [t]-\end{code}--\section{Morphological realisation}--\jargon{Morphological realisation} refers to the actual process-of converting lemmas and morphological information into inflected forms.-We do this by calling some third party software specified by the user.--The morphological software must accept a JSON list of \jargon{lemma sentences}-where each lemma sentence is itself a list of objects containing a lemma and-a feature structure.--\begin{verbatim}-[- [{"lemma": "le",       "lemma-features": "[num:sg gen:f]"},-  {"lemma": "fille",    "lemma-features": "[num:sg]"},-  {"lemma": "detester", "lemma-features": "[num:sg tense:past]"},-  {"lemma": "le",       "lemma-features": "[num:pl gen:m]"},-  {"lemma": "garcon",   "lemma-features": "[num:pl]"}- ],-- [{"lemma": "ce",       "lemma-features": "[]"},-  {"lemma": "etre",     "lemma-features": "[]"},-  {"lemma": "le",       "lemma-features": "[]"},-  {"lemma": "garcon",   "lemma-features": "[]"},-  {"lemma": "que",      "lemma-features": "[]"},-  {"lemma": "le",       "lemma-features": "[num:sg gen:f]"},-  {"lemma": "fille",    "lemma-features": "[num:sg]"},-  {"lemma": "detester", "lemma-features": "[num:sg tense:past]"}- ]-]-\end{verbatim}--NB: I recommend using a JSON library instead of parsing and writing this by-hand.--The morphological realiser may return more than one output per sentence.-Indeed, we expect a JSON-formatted list (a) of lists (b), where each (b)-provides a number of candidate morphological realisations for a sentence in-(a).  The list (a) must have the same length as the input because each item in-(a) is expected to correspond to a sentence from the input.--Notice that the morphological generator can choose to delete spaces or do other-orthographical tricks in between words:--\begin{verbatim}-[- ["la fille detestait les garcons"],-- ["c'est le garcon que la fille detestait"- ,"c'est les garcons que la fille detestait"]-]-\end{verbatim}--If your morphological software does not do this, you could wrap it with a-simple script.--\begin{code}--- | Extracts the lemmas from a list of uninflected sentences.  This is used---   when the morphological generator is unavailable, doesn't work, etc.-sansMorph :: LemmaPlusSentence -> [String]-sansMorph = singleton . unwords . map lem- where-  lem (LemmaPlus l _) = l---- | Converts a list of uninflected sentences into inflected ones by calling----  the third party software.--- FIXME: this doesn't actually support lists-of-results per input--- will need to work it out-inflectSentencesUsingCmd :: String -> [LemmaPlusSentence] -> IO [(LemmaPlusSentence,[String])]-inflectSentencesUsingCmd morphcmd sentences =-  do -- run the inflector-     (toP, fromP, _, _) <- runInteractiveCommand morphcmd-     hPutStrLn toP . render . pp_value . showJSON $ sentences-     hClose toP-     -- read the inflector output back as a list of strings-     mResults <- (resultToEither . decode) `fmap` hGetContents fromP-     case mResults of-       Left err  -> fallback $ "Could not parse morphological generator output: " ++ err-       Right res -> do let lenResults   = length res-                           lenSentences = length sentences-                       if lenResults == lenSentences-                          then return $ zip sentences res-                          else fallback $ "Morphological generator returned "-                                          ++ show lenResults ++ " results for "-                                          ++ show lenSentences ++ " inputs"-                    `catch` \e -> fallback $ "Error calling morphological generator:\n" ++ show e- where-  fallback err =-    do ePutStrLn err-       return $ map (\x -> (x, sansMorph x)) sentences--singleton :: a -> [a]-singleton x = [x]-\end{code}
+ src/NLP/GenI/Morphology/Types.hs view
@@ -0,0 +1,104 @@+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE DeriveDataTypeable #-}+-- GenI surface realiser+-- Copyright (C) 2005 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.++module NLP.GenI.Morphology.Types where++import Control.Applicative ((<$>),(<*>))+import Control.DeepSeq+import Data.Text ( Text )++import NLP.GenI.GeniVal ( GeniVal )+import NLP.GenI.FeatureStructure ( Flist )+import NLP.GenI.Parser ( geniFeats, Parser, runParser )+import NLP.GenI.Pretty+import NLP.GenI.Semantics+import Text.JSON++-- ----------------------------------------------------------------------+-- morph input+-- ----------------------------------------------------------------------++type MorphInputFn = Literal GeniVal -> Maybe (Flist GeniVal)++-- ----------------------------------------------------------------------+-- morph output+-- ----------------------------------------------------------------------++type MorphRealiser = [LemmaPlusSentence] -> [MorphOutput]++data MorphOutput = MorphOutput { moWarnings     :: [Text]+                               , moRealisations :: [Text]+                               }+  deriving (Ord, Eq)++instance JSON MorphOutput where+ readJSON j =+   case fromJSObject `fmap` readJSON j of+     Error _ -> MorphOutput [] <$> readJSON j+     Ok jo   -> do+       let field x = maybe (fail $ "Could not find: " ++ x) readJSON+                   $ lookup x jo+           warnings = maybe (return []) readJSON (lookup "warnings" jo)+       MorphOutput <$> warnings+                   <*> field "realisations"+ showJSON _ = error "Don't know how to render MorphOutput"++-- | A lemma plus its morphological features+data LemmaPlus = LemmaPlus+    { lpLemma :: Text+    , lpFeats :: Flist GeniVal+    }+ deriving (Eq, Ord)++-- | A sentence composed of 'LemmaPlus' instead of plain old words+type LemmaPlusSentence = [LemmaPlus]++instance JSON LemmaPlus where+ readJSON j =+    do jo <- fromJSObject `fmap` readJSON j+       let field x = maybe (fail $ "Could not find: " ++ x) readJSON+                   $ lookup x jo+       LemmaPlus <$> field "lemma"+                 <*> (parsecToJSON "lemma-features" geniFeats =<< field "lemma-features")+ showJSON (LemmaPlus l fs) =+     JSObject . toJSObject $ [ ("lemma", showJSON l)+                             , ("lemma-features", showJSON $ prettyStr fs)+                             ]++parsecToJSON :: Monad m => String -> Parser b -> String -> m b+parsecToJSON description p str =+ case runParser p () "" str of+   Left  err -> fail $ "Couldn't parse " ++ description ++ " because " ++ show err+   Right res -> return res++{-!+deriving instance NFData MorphOutput+deriving instance NFData LemmaPlus+!-}++-- GENERATED START++ +instance NFData MorphOutput where+        rnf (MorphOutput x1 x2) = rnf x1 `seq` rnf x2 `seq` ()++ +instance NFData LemmaPlus where+        rnf (LemmaPlus x1 x2) = rnf x1 `seq` rnf x2 `seq` ()+-- GENERATED STOP
+ src/NLP/GenI/OptimalityTheory.hs view
@@ -0,0 +1,343 @@+-- GenI surface realiser+-- Copyright (C) 2009 Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.++{-# LANGUAGE OverloadedStrings #-}+module NLP.GenI.OptimalityTheory+   ( -- * Input+     OtConstraint(..), OtRanking,+     -- * Output+     GetTraces, OtResult, OtViolation, RankedOtConstraint(..),+     rankResults, otWarnings,+     -- * Display+     prettyViolations,prettyRank+   )+ where++import Control.Applicative ( (<$>), (<*>) )+import Control.Arrow ( first )+import Data.Function (on)+import Data.Char ( isSpace )+import Data.List (nub, partition, sort, sortBy, groupBy, (\\), unfoldr )+import Data.Text ( Text )+import qualified Data.Text as T+import Text.JSON++import NLP.GenI.Pretty+import NLP.GenI.TreeSchema ( Macros, ptrace )+import qualified NLP.GenI.Builder as B++import Control.DeepSeq++data OtConstraint = PositiveC Text -- ^ the trace must appear+                  | NegativeC Text -- ^ the trace must NOT appear+                  | NegativeConjC [Text] -- ^ these traces must not appear AT THE SAME TIME+ deriving (Show, Eq)++data RankedOtConstraint = RankedOtConstraint Int OtConstraint+ deriving (Show, Eq)++instance Ord RankedOtConstraint where+ compare (RankedOtConstraint r1 _) (RankedOtConstraint r2 _) = compare r1 r2++-- | Same as 'RankedOtConstraint' with the sorting inverted+newtype RankedOtConstraint2 = RankedOtConstraint2 RankedOtConstraint deriving Eq++instance Ord RankedOtConstraint2 where+ compare (RankedOtConstraint2 x) (RankedOtConstraint2 y) = compare y x+++type OtRanking = [[OtConstraint]]++data OtViolation = OtViolation { otLexName            :: Text -- ^ empty for global+                               , otConstraintViolated :: RankedOtConstraint }+ deriving (Show, Eq, Ord)++data LexItem = LexItem+    { lLexname :: Text+    , lTraces  :: [Text]+    }+  deriving (Ord, Eq, Show)++type GetTraces = Text -> [Text]+type OtResult x = (Int,x,[OtViolation])++instance JSON OtConstraint where+ readJSON j =+    do jv <- fromJSObject `fmap` readJSON j+       case lookup "pos-constraint" jv of+        Just v    -> PositiveC `fmap` readJSON v+        Nothing   -> case lookup "neg-constraint" jv of+         Just v   -> NegativeC `fmap` readJSON v+         Nothing  -> case lookup "neg-conj-constraint" jv of+          Just v  -> NegativeConjC `fmap` readJSONs v+          Nothing -> fail $ "Could not read OtConstraint"+ showJSON (PositiveC c) =+     JSObject . toJSObject $ [ ("pos-constraint", showJSON c ) ]+ showJSON (NegativeC c) =+     JSObject . toJSObject $ [ ("neg-constraint", showJSON c ) ]+ showJSON (NegativeConjC cs) =+     JSObject . toJSObject $ [ ("neg-conj-constraint", showJSONs cs ) ]++-- ---------------------------------------------------------------------+-- top level stuff+-- ---------------------------------------------------------------------+otWarnings :: Macros -> OtRanking -> [OtViolation] -> [Text]+otWarnings gram ranking blocks =+    addWarning neTraces neTracesW+  . addWarning nvConstraints nvConstraintsW+  $ []+ where+  addWarning xs w = if null xs then id else (w xs :)+  neTracesW xs = "these traces never appear in the grammar: " `T.append` T.unwords xs+  neTraces  = nonExistentTraces gram ranking+  nvConstraintsW xs = "these constraints are never violated: "+      `T.append` T.unwords (map pretty xs)+  nvConstraints = neverViolated blocks ranking++rankResults :: GetTraces -> (a -> B.TagDerivation) -> OtRanking -> [a] -> [OtResult a] --changed type Derivation+rankResults getTraces getDerivation r = squish . sortResults . map addViolations+ where+   addViolations x = (x, getViolations x)+   getViolations  = violations (concatRank r) . lexTraces getTraces . getDerivation+   squish         = concat . zipWith applyRank [1..]+   applyRank i    = map (\(x,vs) -> (i,x,vs))++-- ---------------------------------------------------------------------+-- detecting violations+-- ---------------------------------------------------------------------++violations :: [RankedOtConstraint] -> [LexItem] -> [OtViolation]+violations cs ls = posVs ls ++ negVs ls+ where+  negVs  = concatMap (\l -> negViolations cs (lLexname l) (lTraces l))+  posVs  = posViolations cs . concatMap lTraces++-- | A positive constraint is violated when a trace is NOT present+posViolations :: [RankedOtConstraint] -> [Text] -> [OtViolation]+posViolations cs ss =+ [ OtViolation "" c | c@(RankedOtConstraint _ (PositiveC s)) <- cs, not (s `elem` ss) ]++-- | A negative constraint is violated when a trace is present+--+--   Note that we will not notice if a constraint is violated more+--   than once.  If you want to count multiple violations, you'll+--   either need to partition the input strings and map this function+--   on each sublist or rewrite this code.+negViolations :: [RankedOtConstraint]+              -> Text     -- ^ lex name+              -> [Text]   -- ^ traces+              -> [OtViolation]+negViolations cs l ss =+ [ OtViolation l c | c@(RankedOtConstraint _ (NegativeC s)) <- cs, s `elem` ss ] +++ [ OtViolation l c | c@(RankedOtConstraint _ (NegativeConjC xs)) <- cs, all (`elem` ss) xs ]++-- | Violations sorted so that the highest ranking constraint+--   (smallest number) goes first+sortedViolations :: (a, [OtViolation]) -> [RankedOtConstraint2]+sortedViolations = map (RankedOtConstraint2 . otConstraintViolated) . sort . snd++-- | Sort the sentences so that the ones with the *lowest*+--   ranking violations (biggest number) go first.+--   Note that we return in groups for the sake of ties.+sortResults :: [(a, [OtViolation])] -> [[(a, [OtViolation])]]+sortResults = sortAndGroupByDecoration compare sortedViolations++lexTraces :: GetTraces -> B.TagDerivation -> [LexItem] --changed type Derivation+lexTraces getTraces = map (toLexItem getTraces) . B.lexicalSelection++toLexItem :: GetTraces -> Text -> LexItem+toLexItem getTraces t =+    LexItem { lLexname = t+            , lTraces  = getTraces t+            }++-- ----------------------------------------------------------------------+-- Output format+-- ----------------------------------------------------------------------++instance JSON RankedOtConstraint where+ readJSON j =+    do jo <- fromJSObject `fmap` readJSON j+       let field x = maybe (fail $ "Could not find: " ++ x) readJSON+                   $ lookup x jo+       RankedOtConstraint <$> field "rank"+                          <*> field "violation"+ showJSON = JSObject . toJSObject . rankedOtConstraintToPairs++rankedOtConstraintToPairs :: RankedOtConstraint -> [ (String, JSValue) ]+rankedOtConstraintToPairs (RankedOtConstraint r c) =+  [ ("rank", showJSON r), ("violation", showJSON c) ]++instance JSON OtViolation where+ readJSON j =+    do jo <- fromJSObject `fmap` readJSON j+       case lookup "lex-item" jo of+         Nothing -> OtViolation "" <$> readJSON j+         Just l  -> OtViolation <$> readJSON l+                                <*> readJSON j++ showJSON ov = JSObject . toJSObject $ pairs+  where+   pairs = case otLexName ov of+             "" -> basicPairs+             l  -> ("lex-item", showJSON l) : basicPairs+   basicPairs = rankedOtConstraintToPairs (otConstraintViolated ov)++-- ---------------------------------------------------------------------+-- pretty printing+-- ---------------------------------------------------------------------++-- TODO: Return as a pretty Doc+prettyViolations :: GetTraces -> Bool -> [OtViolation] -> Text+prettyViolations getTraces noisy vs =+    T.unlines $+        [ indented 1 75 (showPosVs posVs) | not (null posVs) ]+        ++ map showLexVs negBuckets+  where+    (posVs, negVs) = partition (T.null . otLexName) vs+    negBuckets = buckets otLexName negVs+    --+    showPosVs = T.unwords . map prettyV+    showLexVs (l,lvs) =+        (indented 2 75 . T.unwords $ parens l : map prettyV lvs) `T.append`+        (if noisy then "\n" `T.append` allTraces l else "")+      where+        allTraces = indented 4 75 . T.unwords . getTraces+    prettyV = pretty . otConstraintViolated++instance Pretty RankedOtConstraint where+    pretty (RankedOtConstraint r c) = pretty c <+> prettyRank r++instance Pretty OtConstraint where+    pretty (PositiveC str) = '+' `T.cons` str+    pretty (NegativeC str) = '*' `T.cons` str+    pretty (NegativeConjC strs) =+        '*' `T.cons` (parens . T.intercalate " & " $ strs)++prettyRank :: Int -> Text+prettyRank r = parens $ 'r' `T.cons` T.pack (show r)++-- ---------------------------------------------------------------------+-- detecting impossible constraints or other potential errors+-- ---------------------------------------------------------------------++neverViolated :: [OtViolation] -> [[OtConstraint]] -> [OtConstraint]+neverViolated vs ranking = concat ranking \\ cs_used+ where+  cs_used = nub . map (noRank . otConstraintViolated) $ vs++nonExistentTraces :: Macros -> [[OtConstraint]] -> [Text]+nonExistentTraces ms vs = r_traces \\ m_traces+ where+  m_traces = nub $ concatMap ptrace ms+  r_traces = nub $ concatMap cTraces $ concat vs++cTraces :: OtConstraint -> [Text]+cTraces (PositiveC c) = [c]+cTraces (NegativeConjC cs) = cs+cTraces (NegativeC c) = [c]++-- ----------------------------------------------------------------------+-- helpers+-- ----------------------------------------------------------------------++concatRank :: [[OtConstraint]] -> [RankedOtConstraint]+concatRank = concat . zipWith rank [1..]+ where+  rank x ys = map (RankedOtConstraint x) ys++noRank :: RankedOtConstraint -> OtConstraint+noRank (RankedOtConstraint _ c) = c++-- ----------------------------------------------------------------------+-- odds and ends+-- ----------------------------------------------------------------------++buckets :: Ord b => (a -> b) -> [a] -> [ (b,[a]) ]+buckets f = map (first head . unzip)+          . groupBy ((==) `on` fst)+          . sortBy (compare `on` fst)+          . map (\x -> (f x, x))++-- | Results are grouped so that ties can be noticed+sortAndGroupByDecoration :: Eq b => (b -> b -> Ordering) -> (a -> b) -> [a] -> [[a]]+sortAndGroupByDecoration cmp f = map (map snd)+                               . groupBy ((==) `on` fst)+                               . sortBy (cmp `on` fst)+                               . map (\x -> (f x, x))++indented :: Int -> Int -> Text -> Text+indented x len = T.intercalate "\n"+               . map (\s -> spaces x `T.append` s)+               . wordWrap len++spaces :: Int -> Text+spaces n = T.pack (replicate n ' ')++-- | Whitespace-sensitive wrapping+--+--   Properties:+--+--   * Only splits at whitespace+--+--   * Lines at most @len@ characters long, whitespace permitting+wordWrap :: Int    -- ^ wrap after these many characters+         -> Text+         -> [Text]+wordWrap len =+    unfoldr f+  where+    f t = if T.null t then Nothing else Just (splitAtBefore len t)++splitAtBefore :: Int -- ^ wrap after these many characters +              -> Text+              -> (Text, Text)+splitAtBefore len xs+    | T.length xs < len = (xs, "")+    | T.any isSpace xs  = (begin, end)+    | otherwise         = (xs, "")+  where+    begin =+        if T.length upToSpace > len+           then upToSpace -- ugh! that's one massive line+           else T.stripEnd . T.dropWhileEnd isNotSpace . T.take len $ xs+    end = T.stripStart $ T.drop (T.length begin) xs+    upToSpace  = T.stripStart xs+    isNotSpace = not . isSpace++{-!+deriving instance NFData OtViolation+deriving instance NFData RankedOtConstraint+deriving instance NFData OtConstraint+!-}++-- GENERATED START++ +instance NFData OtViolation where+        rnf (OtViolation x1 x2) = rnf x1 `seq` rnf x2 `seq` ()++ +instance NFData RankedOtConstraint where+        rnf (RankedOtConstraint x1 x2) = rnf x1 `seq` rnf x2 `seq` ()++ +instance NFData OtConstraint where+        rnf (PositiveC x1) = rnf x1 `seq` ()+        rnf (NegativeC x1) = rnf x1 `seq` ()+        rnf (NegativeConjC x1) = rnf x1 `seq` ()+-- GENERATED STOP
− src/NLP/GenI/OptimalityTheory.lhs
@@ -1,390 +0,0 @@-% GenI surface realiser-% Copyright (C) 2009 Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.--\chapter{Ranking output}-\label{cha:ranking}--\begin{code}-module NLP.GenI.OptimalityTheory-   ( -- * Input-     OtConstraint(..), OtRanking,-     -- * Output-     GetTraces, OtResult, OtViolation, RankedOtConstraint(..),-     rankResults, otWarnings,-     -- * Display-     prettyViolations,prettyRank-   )- where--import Control.Applicative ( (<$>), (<*>) )-import Control.Arrow ( first )-import Data.Function (on)-import Data.Char ( isSpace )-import Data.List (nub, partition, sort, sortBy, groupBy, intersperse, (\\), unfoldr )-import Text.JSON--import NLP.GenI.Btypes ( Macros, ptrace )-import qualified NLP.GenI.Builder as B-\end{code}--If your tree schemata are annotated with traces (TODO link to traces and-metagrammars), you can re-use them as a basis for ranking the output produced-by GenI.  The basic idea is to supply a list of either positive, negative or-negative conjunction constraints.--For users familiar with Haskell, the constraints are described with the-following type:-\begin{includecodeinmanual}-\begin{code}-data OtConstraint = PositiveC String -- ^ the trace must appear-                  | NegativeC String -- ^ the trace must NOT appear-                  | NegativeConjC [String] -- ^ these traces must not appear AT THE SAME TIME- deriving (Show, Eq)-\end{code}-\end{includecodeinmanual}--Roughly speaking the more highly ranked the constraint, the greater the impact-of a violation of that constraint will be.  See section-\ref{sec:ranking-procedure} for more details on the ranking procedure.--\begin{code}-data RankedOtConstraint = RankedOtConstraint Int OtConstraint- deriving (Show, Eq)--instance Ord RankedOtConstraint where- compare (RankedOtConstraint r1 _) (RankedOtConstraint r2 _) = compare r1 r2---- | Same as 'RankedOtConstraint' with the sorting inverted-newtype RankedOtConstraint2 = RankedOtConstraint2 RankedOtConstraint deriving Eq--instance Ord RankedOtConstraint2 where- compare (RankedOtConstraint2 x) (RankedOtConstraint2 y) = compare y x---type OtRanking = [[OtConstraint]]--data OtViolation = OtViolation { otLexName            :: String -- ^ empty for global-                               , otConstraintViolated :: RankedOtConstraint }- deriving (Show, Eq, Ord)--data LexItem = LexItem-       { lLexname :: String-       , lTraces :: [String]-       } deriving (Ord, Eq, Show)--type GetTraces = String -> [String]-type OtResult x = (Int,x,[OtViolation])-\end{code}--\section{Input format}--Constraints are expressed in JSON as a list of \jargon{ranking levels}.  A-ranking level is a list of constraints that should be assigned the same rank.-In lieu of a formal description, we provide an example below:-\small{NB: Either the JSON format or the JSON parser used by GenI is strict-enough to refuse initial whitespace in this file.}--\begin{verbatim}-[- [{"neg-constraint": "dian0Vn1dePassive"},-  {"pos-constraint": "CanonicalSubject"}],-- [{"neg-conj-constraint": ["InvertedNominalSubject",-                           "CanonicalSententialObjectFinite"]}],-- [{"neg-conj-constraint": ["InvertedNominalSubject",-                           "UnboundedCleft"]},-  {"neg-constraint": "CleftSubject"}]-]-\end{verbatim}--This example constraints file has three ranking levels.  These levels contain-following constraints:--\begin{enumerate}-\item A negative constraint saying that \verb!dian0Vn1dePassive! should-      not appear, and a positive one saying that \verb!CanonicalSubject!-      \emph{should} appear.  These constraints appear together only because-      the author of the example thinks they should have the same rank,-      not because there is neccesarily any inherent relationship between-      them.-\item A single negative conjunction constraint saying that-      \verb!InvertedNominalSubject! and-      \verb!CanonicalSententialObjectFinite!-      should not appear together.-\item A negative conjunction constraint saying tat-      \verb!InvertedNominalSubject! and \verb!UnboundedCleft! should not-      appear together; and also a negative constraints saying that-      \verb!CleftSubject! should not appear.  As with the first ranking-      level, there is no relationship between these two constraints.  We-      just put them on the same level to give them the same rank-\end{enumerate}--\begin{code}-instance JSON OtConstraint where- readJSON j =-    do jv <- fromJSObject `fmap` readJSON j-       case lookup "pos-constraint" jv of-        Just v    -> PositiveC `fmap` readJSON v-        Nothing   -> case lookup "neg-constraint" jv of-         Just v   -> NegativeC `fmap` readJSON v-         Nothing  -> case lookup "neg-conj-constraint" jv of-          Just v  -> NegativeConjC `fmap` readJSONs v-          Nothing -> fail $ "Could not read OtConstraint"- showJSON (PositiveC c) =-     JSObject . toJSObject $ [ ("pos-constraint", showJSON c ) ]- showJSON (NegativeC c) =-     JSObject . toJSObject $ [ ("neg-constraint", showJSON c ) ]- showJSON (NegativeConjC cs) =-     JSObject . toJSObject $ [ ("neg-conj-constraint", showJSONs cs ) ]-\end{code}--\begin{code}--- ------------------------------------------------------------------------ top level stuff--- ----------------------------------------------------------------------otWarnings :: Macros -> OtRanking -> [OtViolation] -> [String]-otWarnings gram ranking blocks =-    addWarning neTraces neTracesW-  . addWarning nvConstraints nvConstraintsW-  $ []- where-  addWarning xs w = if null xs then id else (w xs :)-  neTracesW xs = "these traces never appear in the grammar: " ++ unwords xs-  neTraces  = nonExistentTraces gram ranking-  nvConstraintsW xs = "these constraints are never violated: " ++ unwords (map prettyConstraint xs)-  nvConstraints = neverViolated blocks ranking--rankResults :: GetTraces -> (a -> B.Derivation) -> OtRanking -> [a] -> [OtResult a]-rankResults getTraces getDerivation r = squish . sortResults . map addViolations- where-   addViolations x = (x, getViolations x)-   getViolations  = violations (concatRank r) . lexTraces getTraces . getDerivation-   squish         = concat . zipWith applyRank [1..]-   applyRank i    = map (\(x,vs) -> (i,x,vs))-\end{code}---\begin{code}--- ------------------------------------------------------------------------ detecting violations--- -----------------------------------------------------------------------violations :: [RankedOtConstraint] -> [LexItem] -> [OtViolation]-violations cs ls = posVs ls ++ negVs ls- where-  negVs  = concatMap (\l -> negViolations cs (lLexname l) (lTraces l))-  posVs  = posViolations cs . concatMap lTraces---- | A positive constraint is violated when a trace is NOT present-posViolations :: [RankedOtConstraint] -> [String] -> [OtViolation]-posViolations cs ss =- [ OtViolation "" c | c@(RankedOtConstraint _ (PositiveC s)) <- cs, not (s `elem` ss) ]---- | A negative constraint is violated when a trace is present------   Note that we will not notice if a constraint is violated more---   than once.  If you want to count multiple violations, you'll---   either need to partition the input strings and map this function---   on each sublist or rewrite this code.-negViolations :: [RankedOtConstraint]-              -> String   -- ^ lex name-              -> [String] -- ^ traces-              -> [OtViolation]-negViolations cs l ss =- [ OtViolation l c | c@(RankedOtConstraint _ (NegativeC s)) <- cs, s `elem` ss ] ++- [ OtViolation l c | c@(RankedOtConstraint _ (NegativeConjC xs)) <- cs, all (`elem` ss) xs ]-\end{code}--\section{Ranking procedure}-\label{sec:ranking-procedure}--Generation results are sorted according to their highest-ranking constraint-violation (moving on to the next-highest ranking violation and so forth in case-of a tie).  The best result appears first.--\begin{code}--- | Violations sorted so that the highest ranking constraint---   (smallest number) goes first-sortedViolations :: (a, [OtViolation]) -> [RankedOtConstraint2]-sortedViolations = map (RankedOtConstraint2 . otConstraintViolated) . sort . snd---- | Sort the sentences so that the ones with the *lowest*---   ranking violations (biggest number) go first.---   Note that we return in groups for the sake of ties.-sortResults :: [(a, [OtViolation])] -> [[(a, [OtViolation])]]-sortResults = sortAndGroupByDecoration compare sortedViolations--lexTraces :: GetTraces -> B.Derivation -> [LexItem]-lexTraces getTraces = map (toLexItem getTraces) . B.lexicalSelection--toLexItem :: GetTraces -> String -> LexItem-toLexItem getTraces t =- LexItem { lLexname = t-         , lTraces  = getTraces t }-\end{code}--\section{Output format}--Constraint violations can be outputted as JSON objects as the following example-shows--\begin{verbatim}-  { "lex-item": "discuter:n0Vn1pn2:Tn0Vn1pn2-5830:22",-  , "rank": 6,-  , "violation": {"neg-constraint": "passiveVerbMorphology"}-  }-\end{verbatim}--Positive constraint violations are not associated with any lexical items-so the lex-item field is omitted for them.--\begin{code}--- ------------------------------------------------------------------------ output--- ----------------------------------------------------------------------instance JSON RankedOtConstraint where- readJSON j =-    do jo <- fromJSObject `fmap` readJSON j-       let field x = maybe (fail $ "Could not find: " ++ x) readJSON-                   $ lookup x jo-       RankedOtConstraint <$> field "rank"-                          <*> field "violation"- showJSON = JSObject . toJSObject . rankedOtConstraintToPairs--rankedOtConstraintToPairs :: RankedOtConstraint -> [ (String, JSValue) ]-rankedOtConstraintToPairs (RankedOtConstraint r c) =-  [ ("rank", showJSON r), ("violation", showJSON c) ]--instance JSON OtViolation where- readJSON j =-    do jo <- fromJSObject `fmap` readJSON j-       case lookup "lex-item" jo of-         Nothing -> OtViolation "" <$> readJSON j-         Just l  -> OtViolation <$> readJSON l-                                <*> readJSON j-- showJSON ov = JSObject . toJSObject $ pairs-  where-   pairs = case otLexName ov of-             "" -> basicPairs-             l  -> ("lex-item", showJSON l) : basicPairs-   basicPairs = rankedOtConstraintToPairs (otConstraintViolated ov)---- ------------------------------------------------------------------------ pretty printing--- ------------------------------------------------------------------------- TODO: Return as a pretty Doc-prettyViolations :: GetTraces -> Bool -> [OtViolation] -> String-prettyViolations getTraces noisy vs =-   unlines $ (if null posVs then []  else [ indented 1 75 . showPosVs $ posVs ])-           ++ map showLexVs negBuckets- where-  (posVs, negVs) = partition (null . otLexName) vs-  negBuckets = buckets otLexName negVs-  ---  showPosVs  = unwords . map (prettyRankedConstraint . otConstraintViolated)-  showLexVs (l,lvs) =-    let itmName = "(" ++ l ++ ")"-        constraints = map otConstraintViolated lvs-        allTraces = indented 4 75 . unwords . getTraces $ l-    in (indented 2 75 . unwords $ itmName : map prettyRankedConstraint constraints)-       ++ (if noisy then "\n" ++ allTraces else "")--prettyRankedConstraint :: RankedOtConstraint -> String-prettyRankedConstraint (RankedOtConstraint r c) = prettyConstraint c ++ " " ++ prettyRank r--prettyConstraint :: OtConstraint -> String-prettyConstraint (PositiveC str) = '+' : str-prettyConstraint (NegativeC str) = '*' : str-prettyConstraint (NegativeConjC strs) = "*(" ++ (concat $ intersperse " & " strs) ++ ")"--prettyRank :: Int -> String-prettyRank r = "(r" ++ show r ++ ")"---- ------------------------------------------------------------------------ detecting impossible constraints or other potential errors--- -----------------------------------------------------------------------neverViolated :: [OtViolation] -> [[OtConstraint]] -> [OtConstraint]-neverViolated vs ranking = concat ranking \\ cs_used- where-  cs_used = nub . map (noRank . otConstraintViolated) $ vs--nonExistentTraces :: Macros -> [[OtConstraint]] -> [String]-nonExistentTraces ms vs = r_traces \\ m_traces- where-  m_traces = nub $ concatMap ptrace ms-  r_traces = nub $ concatMap cTraces $ concat vs--cTraces :: OtConstraint -> [String]-cTraces (PositiveC c) = [c]-cTraces (NegativeConjC cs) = cs-cTraces (NegativeC c) = [c]---- ------------------------------------------------------------------------- helpers--- ------------------------------------------------------------------------concatRank :: [[OtConstraint]] -> [RankedOtConstraint]-concatRank = concat . zipWith rank [1..]- where-  rank x ys = map (RankedOtConstraint x) ys--noRank :: RankedOtConstraint -> OtConstraint-noRank (RankedOtConstraint _ c) = c---- ------------------------------------------------------------------------- odds and ends--- ------------------------------------------------------------------------buckets :: Ord b => (a -> b) -> [a] -> [ (b,[a]) ]-buckets f = map (first head . unzip)-          . groupBy ((==) `on` fst)-          . sortBy (compare `on` fst)-          . map (\x -> (f x, x))---- | Results are grouped so that ties can be noticed-sortAndGroupByDecoration :: Eq b => (b -> b -> Ordering) -> (a -> b) -> [a] -> [[a]]-sortAndGroupByDecoration cmp f = map (map snd)-                               . groupBy ((==) `on` fst)-                               . sortBy (cmp `on` fst)-                               . map (\x -> (f x, x))--indented :: Int -> Int -> String -> String-indented x len = concat . intersperse "\n" . map (\s -> spaces x ++ s) . unfoldr f- where-  f ""  = Nothing-  f str = Just $ splitAtBefore len str--spaces :: Int -> String-spaces n = replicate n ' '--splitAtBefore :: Int -> String -> (String, String)-splitAtBefore len xs-  | length xs < len = (xs, "")-  | any isSpace xs  = (begin, trim $ drop (length begin) xs)-  | otherwise       = (xs, "")- where-  begin-   | length upToSpace > len = upToSpace-   | otherwise = reverse . trim . dropWhile isNotSpace . reverse . take len $ xs-  upToSpace = takeWhile isNotSpace xs-  isNotSpace = not . isSpace-  trim = drop 1-\end{code}
+ src/NLP/GenI/Parser.hs view
@@ -0,0 +1,633 @@+-- GenI surface realiser+-- Copyright (C) 2005 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.++{-# LANGUAGE CPP, FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# OPTIONS_GHC -fno-warn-unused-do-bind #-}+module NLP.GenI.Parser (+  -- * Test suites+  geniTestSuite, geniSemanticInput, geniTestSuiteString,+  geniDerivations,+  toSemInputString,+  -- * Trees+  geniMacros, geniTagElems,+  -- * Lexicon and morph+  geniLexicon, geniMorphInfo,+  -- * Basics+  geniFeats, geniSemantics, geniValue, geniWords,+  -- * Helpers+  geniWord, geniLanguageDef, tillEof,+  --+  parseFromFile, -- UTF-8 version+  module Text.Parsec,+  module Text.Parsec.String,+) where+++import Control.Applicative ( (<*>), (<$>), (*>), (<*) )+import Control.Monad (liftM, when)+import Data.Text ( Text )+import Text.Parsec+import Text.Parsec.String hiding ( parseFromFile ) -- TODO: replace with Text.Parsec.Text+import Text.Parsec.Language (emptyDef)+import Text.Parsec.Token (TokenParser,+    LanguageDef,+    commentLine, commentStart, commentEnd, opLetter,+    reservedOpNames, reservedNames, identLetter, identStart, +    makeTokenParser)+import qualified Data.Map  as Map+import qualified Data.Text as T+import qualified Data.Tree as T+import qualified System.IO.UTF8 as UTF8+--import qualified Text.Parsec.Expr  as P+import qualified Text.Parsec.Token as P++import NLP.GenI.FeatureStructure ( Flist, AvPair(..), sortFlist )+import NLP.GenI.General (isGeniIdentLetter)+import NLP.GenI.GeniShow ( GeniShow(..), geniKeyword )+import NLP.GenI.GeniVal ( GeniVal, mkGConst, mkGConstNone, mkGVar, mkGAnon, isAnon )+import NLP.GenI.Lexicon ( fromLexSem, mkFullLexEntry, LexEntry(..) )+import NLP.GenI.Pretty ( above )+import NLP.GenI.Semantics ( Literal(..), Sem, sortSem, LitConstr, SemInput )+import NLP.GenI.Tag (TagElem(..), setTidnums)+import NLP.GenI.TestSuite ( TestCase(..) )+import NLP.GenI.TreeSchema (SchemaTree, Ttree(..), Ptype(..), GNode(..), GType(..) )++-- import BoolExp+import Data.FullList ( FullList, Listable(..) )+++-- General notes++-- reserved words+#define SEMANTICS       "semantics"+#define SENTENCE        "sentence"+#define OUTPUT          "output"+#define TRACE           "trace"+#define ANCHOR          "anchor"+#define SUBST           "subst"+#define FOOT            "foot"+#define LEX             "lex"+#define TYPE            "type"+#define ACONSTR         "aconstr"+#define INITIAL         "initial"+#define AUXILIARY       "auxiliary"+#define IDXCONSTRAINTS  "idxconstraints"+#define BEGIN           "begin"+#define END             "end"++-- Lexer++geniLanguageDef :: LanguageDef ()+geniLanguageDef = emptyDef+         { commentLine = "%"+         , commentStart = "/*"+         , commentEnd = "*/"+         , opLetter = oneOf ""+         , reservedOpNames = [""]+         , reservedNames =+             [ SEMANTICS , SENTENCE, OUTPUT, IDXCONSTRAINTS, TRACE+             , ANCHOR , SUBST , FOOT , LEX , TYPE , ACONSTR+             , INITIAL , AUXILIARY+             , BEGIN , END ]+         , identLetter = identStuff+         , identStart  = identStuff+         }+  where identStuff = satisfy isGeniIdentLetter++geniValue :: Parser GeniVal+geniValue =   ((try $ anonymous) <?> "_ or ?_")+          <|> (constants  <?> "a constant or atomic disjunction")+          <|> (variable   <?> "a variable")+  where+    question = "?"+    disjunction = geniAtomicDisjunction+    constants :: Parser GeniVal+    constants = mkGConst <$> disjunction+    variable :: Parser GeniVal+    variable =+      do symbol question+         v <- identifier+         mcs <- option Nothing $ (symbol "/" >> Just `liftM` disjunction)+         return (mkGVar v mcs)+    anonymous :: Parser GeniVal+    anonymous =+      do optional $ symbol question+         symbol "_"+         return mkGAnon++geniAtomicDisjunction :: Parser (FullList Text)+geniAtomicDisjunction = do+    (x:xs) <- atom `sepBy1` (symbol "|")+    return (x !: xs)+  where+    atom = looseIdentifier <|> stringLiteral++geniFancyDisjunction :: Parser [GeniVal]+geniFancyDisjunction = geniValue `sepBy1` symbol ";"++class GeniValLike v where+  geniValueLike :: Parser v++instance GeniValLike GeniVal where+  geniValueLike = geniValue++instance GeniValLike [GeniVal] where+  geniValueLike = geniFancyDisjunction++-- We make no attempt to check for / guarantee uniqueness here+-- because the same sort of format is used for things which are+-- not strictly speaking feature structures+geniFeats :: GeniValLike v => Parser (Flist v)+geniFeats = option [] $ squares $ many geniAttVal++geniAttVal :: GeniValLike v => Parser (AvPair v)+geniAttVal = do+    att <- identifierR <?> "an attribute"; colon+    val <- geniValueLike <?> "a GenI value"+    return $ AvPair att val++geniSemantics :: Parser Sem+geniSemantics =+  do sem <- many (geniLiteral <?> "a literal")+     return (sortSem sem)++geniLiteral :: Parser (Literal GeniVal)+geniLiteral = geniLiteral_ mkGAnon geniValue++geniLiteral_ :: a -> Parser a -> Parser (Literal a)+geniLiteral_ zero gv =+    Literal <$> (option zero handleParser <?> "a handle")+            <*> (gv <?> "a predicate")+            <*> (parens (many gv) <?> "some parameters")+  where+    handleParser = try $ gv <* char ':'++geniSemanticInput :: Parser (Sem,Flist GeniVal,[LitConstr])+geniSemanticInput =+  do keywordSemantics+     (sem,litC) <- liftM unzip $ squares $ many literalAndConstraint+     idxC       <- option [] geniIdxConstraints+     --+     let sem2     = createHandles sem+         semlitC2 = [ (s,c) | (s,c) <- zip sem2 litC, (not.null) c ]+     return (createHandles sem, idxC, semlitC2)+  where+     -- set all anonymous handles to some unique value+     -- this is to simplify checking if a result is+     -- semantically complete+     createHandles :: Sem -> Sem+     createHandles = zipWith setHandle ([1..] :: [Int])+     --+     setHandle i (Literal h pred_ par) =+       let h2 = if isAnon h+                then mkGConstNone ("genihandle" `T.append` T.pack (show i))+                else h+       in Literal h2 pred_ par+     --+     literalAndConstraint :: Parser LitConstr+     literalAndConstraint =+       do l <- geniLiteral+          t <- option [] $ squares $ many identifier+          return (l,t)++-- | The original string representation of the semantics (for gui)+geniSemanticInputString :: Parser Text+geniSemanticInputString = do+    keywordSemantics+    s <- squaresString+    whiteSpace+    optional geniIdxConstraints+    return s++geniIdxConstraints :: Parser (Flist GeniVal)+geniIdxConstraints = keyword IDXCONSTRAINTS >> geniFeats++{-+geniLitConstraints :: Parser (BoolExp T.Text)+geniLitConstraints =+   P.buildExpressionParser table piece+ where+   piece =  (Cond <$> identifier)+       <|> do { string "~"; Not `liftM` geniLitConstraints }+       <|> parens geniLitConstraints+   table = [ [ op "&" And P.AssocLeft ]+           , [ op "|" Or  P.AssocLeft ]+           ]+   op s f assoc = P.Infix (do { string s ; return f }) assoc+-}++squaresString :: Parser Text+squaresString = do+    char '['+    s <- (T.concat <$> many inSq) <|> squaresString+    char ']'+    return $ "[" `T.append` s `T.append` "]"+  where+    inSq :: Parser Text+    inSq = T.pack <$> many1 (noneOf "[]")++-- the output end of things+-- displaying preformatted semantic input++data SemInputString = SemInputString Text (Flist GeniVal)++instance GeniShow SemInputString where+    geniShowText (SemInputString semStr idxC) =+        geniKeyword SEMANTICS semStr `above` r+      where+        r | null idxC = ""+          | otherwise = geniKeyword IDXCONSTRAINTS (geniShowText idxC)++toSemInputString :: SemInput -> Text -> SemInputString+toSemInputString (_,lc,_) s = SemInputString s lc++geniTestSuite :: Parser [TestCase]+geniTestSuite =+  tillEof (many geniTestCase)++-- | Just the String representations of the semantics+--   in the test suite+geniTestSuiteString :: Parser [Text]+geniTestSuiteString =+    tillEof (many geniTestCaseString)++-- | This is only used by the script genimakesuite+geniDerivations :: Parser [TestCaseOutput]+geniDerivations = tillEof $ many geniOutput++geniTestCase :: Parser TestCase+geniTestCase =+     TestCase <$> (option "" (identifier <?> "a test case name"))+              <*> lookAhead geniSemanticInputString+              <*> geniSemanticInput+              <*> many geniSentence++-- note that the keyword is NOT optional+type TestCaseOutput = (Text, Map.Map (Text,Text) [Text])+geniOutput :: Parser TestCaseOutput+geniOutput = do+    ws <- keyword OUTPUT >> squares geniWords+    ds <- Map.fromList <$> many geniTraces+    return (ws, ds)++geniTraces :: Parser ((Text,Text), [Text])+geniTraces = do+    keyword TRACE+    squares $ do+        k1 <- withWhite geniWord+        k2 <- withWhite geniWord+        whiteSpace >> char '!' >> whiteSpace+        traces <- geniWord `sepEndBy1` whiteSpace+        return ((k1,k2), traces)++withWhite :: Parser a -> Parser a+withWhite p = p >>= (\a -> whiteSpace >> return a)++geniSentence :: Parser Text+geniSentence = optional (keyword SENTENCE) >> squares geniWords++geniWords :: Parser Text+geniWords =+    T.unwords <$> (sepEndBy1 geniWord whiteSpace <?> "a sentence")++geniWord :: Parser Text+geniWord = T.pack <$> many1 (noneOf "[]\v\f\t\r\n ")++-- | The original string representation of a test case semantics+--   (for gui)+geniTestCaseString :: Parser Text+geniTestCaseString = do+    option "" (identifier <?> "a test case name")+    geniSemanticInputString <* (many geniSentence >> many geniOutput)++-- ----------------------------------------------------------------------+-- Lexicon+-- ----------------------------------------------------------------------++geniLexicon :: Parser [LexEntry]+geniLexicon = tillEof $ many1 geniLexicalEntry++geniLexicalEntry :: Parser LexEntry+geniLexicalEntry =+  do lemmas  <- geniAtomicDisjunction <?> "a lemma (or disjunction thereof)"+     family  <- identifier <?> "a tree family"+     (pars, interface) <- option ([],[]) $ parens paramsParser+     equations <- option [] $ do keyword "equations"+                                 geniFeats <?> "path equations"+     filters <- option [] $ do keyword "filters"+                               geniFeats+     keywordSemantics+     (sem, pols) <- fromLexSem <$> squares geniLexSemantics+     --+     return (mkFullLexEntry lemmas family pars interface filters equations sem pols)+  where+    paramsParser :: Parser ([GeniVal], Flist GeniVal)+    paramsParser = do+      pars <- many geniValue <?> "some parameters"+      interface <- option [] $ do symbol "!"+                                  many geniAttVal+      return (pars, interface)++geniLexSemantics :: Parser [Literal PolValue]+geniLexSemantics = sortSem <$> many (geniLexLiteral <?> "a literal")++type PolValue = (GeniVal, Int)++geniLexLiteral :: Parser (Literal PolValue)+geniLexLiteral = geniLiteral_ (mkGAnon,0) geniPolValue++geniPolValue :: Parser (GeniVal, Int)+geniPolValue =+  do p <- geniPolarity+     v <- geniValue+     return (v,p)++-- ----------------------------------------------------------------------+-- Tree schemata+-- ----------------------------------------------------------------------++geniMacros :: Parser [SchemaTree]+geniMacros = tillEof $ many geniTreeDef++initType, auxType :: Parser Ptype+initType = do { reserved INITIAL ; return Initial  }+auxType  = do { reserved AUXILIARY ; return Auxiliar }++geniTreeDef :: Parser SchemaTree+geniTreeDef =+  do sourcePos <- getPosition+     family   <- identifier+     tname    <- option "" (colon *> identifier)+     (pars,iface)   <- geniParams+     theTtype  <- (initType <|> auxType)+     theTree  <- geniTree+     -- sanity checks?+     let treeFail x =+          do setPosition sourcePos -- FIXME does not do what I expect+             fail $ "In tree " ++ T.unpack family ++ ":"+                    ++ T.unpack tname ++ " " ++ show sourcePos ++ ": " ++ x+     let theNodes = T.flatten theTree+         numFeet    = length [ x | x <- theNodes, gtype x == Foot ]+         numAnchors = length [ x | x <- theNodes, ganchor x ]+     when (not $ any ganchor theNodes) $+       treeFail "At least one node in an LTAG tree must be an anchor"+     when (numAnchors > 1) $+       treeFail "There can be no more than 1 anchor node in a tree"+     when (numFeet > 1) $+       treeFail "There can be no more than 1 foot node in a tree"+     when (theTtype == Initial && numFeet > 0) $+       treeFail "Initial trees may not have foot nodes"+     --+     psem     <- option Nothing $ do { keywordSemantics; liftM Just (squares geniSemantics) }+     ptrc     <- option [] $ do { keyword TRACE; squares (many identifier) }+     --+     return TT{ params = pars+              , pfamily = family+              , pidname = tname+              , pinterface = sortFlist iface+              , ptype = theTtype+              , tree = theTree+              , ptrace = ptrc+              , psemantics = psem+              }++geniTree :: (Ord v, GeniValLike v) => Parser (T.Tree (GNode v))+geniTree =+  do node <- geniNode+     kids <- option [] (braces $ many geniTree)+             <?> "child nodes"+     -- sanity checks+     let noKidsAllowed t c = when (c node && (not.null $ kids)) $+             fail $ t ++ " nodes may *not* have any children"+     noKidsAllowed "Anchor"       $ ganchor+     noKidsAllowed "Substitution" $ (== Subs) . gtype+     noKidsAllowed "Foot"         $ (== Foot) . gtype+     --+     return (T.Node node kids)++geniNode :: (Ord v, GeniValLike v) => Parser (GNode v)+geniNode = do+    name      <- identifier+    nodeType  <- geniNodeAnnotation+    lex_   <- if nodeType == AnnoLexeme+                 then ((stringLiteral <|> identifier) `sepBy` symbol "|") <?> "some lexemes"+                 else return []+    constr <- case nodeType of+                  AnnoDefault -> adjConstraintParser+                  AnnoAnchor  -> adjConstraintParser+                  _           -> return True+    -- features only obligatory for non-lex nodes+    (top,bot) <- if nodeType == AnnoLexeme+                    then option ([],[]) $ try topbotParser+                    else topbotParser+    return $ GN { gnname   = name+                , gtype    = fromAnnotation nodeType+                , gup      = sortFlist top+                , gdown    = sortFlist bot+                , glexeme  = lex_+                , ganchor  = nodeType == AnnoAnchor+                , gaconstr = constr+                , gorigin  = ""+                }+  where+    adjConstraintParser = option False $ reserved ACONSTR >> char ':' >> symbol "noadj" >> return True+    topbotParser = do+        top <- geniFeats <?> "top features"+        symbol "!"+        bot <- geniFeats <?> "bot features"+        return (top,bot)++-- | Should be purely internal type to help parsing.+--   Injection to 'GType'.+--+--   We don't just use GType directly because the annotations convey+--   subtle distinctions that aren't encoded, particularly between+--   lexemes and anchors+data Annotation = AnnoAnchor+                | AnnoLexeme+                | AnnoSubst+                | AnnoFoot+                | AnnoDefault+  deriving Eq++fromAnnotation :: Annotation -> GType+fromAnnotation AnnoLexeme  = Lex+fromAnnotation AnnoAnchor  = Lex+fromAnnotation AnnoSubst   = Subs+fromAnnotation AnnoFoot    = Foot+fromAnnotation AnnoDefault = Other++geniNodeAnnotation :: Parser Annotation+geniNodeAnnotation =+    (keyword TYPE *> ty)                   <|>+    (reserved ANCHOR >> return AnnoAnchor) <|>+    return AnnoDefault+  where+    ty    = choice [ try (symbol s) >> return t | (s,t) <- table ]+    table =+        [ (ANCHOR, AnnoAnchor)+        , (FOOT,   AnnoFoot)+        , (SUBST,  AnnoSubst)+        , (LEX,    AnnoLexeme)+        ]++-- | This makes it possible to read anchored trees, which may be+--   useful for debugging purposes.+--+--   FIXME: note that this is very rudimentary; we do not set id numbers,+--   parse polarities. You'll have to call+--   some of our helper functions if you want that functionality.+geniTagElems :: Parser [TagElem]+geniTagElems = tillEof $ setTidnums `fmap` many geniTagElem++geniTagElem :: Parser TagElem+geniTagElem = do+    family   <- identifier+    tname    <- option "" $ (colon *> identifier)+    iface    <- (snd `liftM` geniParams) <|> geniFeats+    theType  <- initType <|> auxType+    theTree  <- geniTree+    sem      <- do { keywordSemantics; squares geniSemantics }+    --+    return $ TE { idname      = tname+                , ttreename   = family+                , tinterface  = iface+                , ttype       = theType+                , ttree       = theTree+                , tsemantics  = sem+                , tidnum      = -1 -- provisional id+                , tpolarities = Map.empty+                , tsempols    = []+                , ttrace      = []+                }++-- | 'geniParams' recognises a list of parameters optionally followed by a+--  bang (\verb$!$) and a list of attribute-value pairs.  This whole thing is+--  to wrapped in the parens.+--+--  TODO: deprecate+geniParams :: Parser ([GeniVal], Flist GeniVal)+geniParams = parens $ do+  pars <- many geniValue <?> "some parameters"+  interface <- option [] $ do { symbol "!"; many geniAttVal }+  return (pars, interface)++-- ----------------------------------------------------------------------+-- Morphology+-- ----------------------------------------------------------------------++geniMorphInfo :: Parser [(Text,Flist GeniVal)]+geniMorphInfo = tillEof $ many morphEntry++morphEntry :: Parser (Text,Flist GeniVal)+morphEntry = (,) <$> identifier <*> geniFeats++-- ======================================================================+-- Everything else+-- ======================================================================++-- ----------------------------------------------------------------------+-- Polarities+-- ----------------------------------------------------------------------++-- | 'geniPolarity' associates a numerical value to a polarity symbol,+--  that is, '+' or '-'.+geniPolarity :: Parser Int+geniPolarity = option 0 (plus <|> minus)+  where+    plus  = do { char '+'; return  1   }+    minus = do { char '-'; return (-1) }++-- ----------------------------------------------------------------------+-- keyword+-- ----------------------------------------------------------------------++{-# INLINE keyword #-}+keyword :: Text -> Parser Text+keyword k =+     (try $ do { reserved k; colon; return k }) <?> T.unpack k ++ ":"++{-# INLINE keywordSemantics #-}+keywordSemantics :: Parser Text+keywordSemantics = keyword SEMANTICS++-- ----------------------------------------------------------------------+-- language def helpers+-- ----------------------------------------------------------------------++lexer :: TokenParser ()+lexer  = makeTokenParser geniLanguageDef++whiteSpace :: Parser ()+whiteSpace = P.whiteSpace lexer++identifier :: Parser Text+identifier = decode <$> P.identifier lexer++-- stolen from Parsec code (ident)+-- | Like 'identifier' but allows for reserved words too+looseIdentifier :: Parser Text+looseIdentifier =+    decode <$> do { i <- ident ; whiteSpace; return i }+  where+    ident = do+        { c <- identStart geniLanguageDef+        ; cs <- many (identLetter geniLanguageDef)+        ; return (c:cs) } <?> "identifier"++colon :: Parser Text+colon = decode <$> P.colon lexer++stringLiteral :: Parser Text+stringLiteral = decode <$> P.stringLiteral lexer++squares, braces, parens :: Parser a -> Parser a+squares = P.squares lexer+braces  = P.braces  lexer+parens  = P.parens  lexer++reserved :: Text -> Parser Text+reserved s = P.reserved lexer (T.unpack s) >> return s++symbol :: Text -> Parser Text+symbol s = P.symbol lexer (T.unpack s) >> return s++decode :: String -> Text+decode = T.pack++-- ----------------------------------------------------------------------+-- parsec helpers+-- ----------------------------------------------------------------------++-- | identifier, permitting reserved words too+identifierR :: Parser Text+identifierR = decode <$> do+    { c <- P.identStart geniLanguageDef+    ; cs <- many (P.identLetter geniLanguageDef)+    ; return (c:cs)+    } <?> "identifier or reserved word"++tillEof :: Parser a -> Parser a+tillEof p = whiteSpace *> p <* eof++-- stolen from Parsec and adapted to use UTF-8 input+parseFromFile :: Parser a -> SourceName -> IO (Either ParseError a)+parseFromFile p fname+    = do{ input <- UTF8.readFile fname+        ; return (parse p fname input)+        }
+ src/NLP/GenI/Polarity.hs view
@@ -0,0 +1,572 @@+-- GenI surface realiser+-- Copyright (C) 2009 Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.++{-# LANGUAGE OverloadedStrings #-}+module NLP.GenI.Polarity(+                module NLP.GenI.Polarity.Types,++                -- * Entry point+                PolAut, PolState(PolSt), AutDebug, PolResult(..),+                buildAutomaton,++                -- * Inner stuff (exported for debugging?)+                makePolAut,+                fixPronouns,+                detectSansIdx, suggestPolFeatures, detectPols, detectPolPaths,+                declareIdxConstraints, detectIdxConstraints,+                prettyPolPaths, prettyPolPaths',++                -- re-exported from Automaton+                automatonPaths, finalSt,+                NFA(states, transitions),+                )+where++import Data.Bits+import qualified Data.Set as Set+import qualified Data.Map as Map+import Data.List+import Data.Maybe (isNothing, isJust)+import Data.Text (Text)+import qualified Data.Text as T++import NLP.GenI.Automaton+import NLP.GenI.FeatureStructure ( Flist, AvPair(..), FeatStruct, unifyFeat )+import NLP.GenI.General+    ( BitVector, isEmptyIntersect, thd3, Interval, ival, (!+!)+    )+import NLP.GenI.GeniVal ( GeniVal(gConstraints), mkGAnon, isAnon, replace )+import NLP.GenI.Polarity.Internal+import NLP.GenI.Polarity.Types+import NLP.GenI.Pretty+import NLP.GenI.Semantics ( Literal(..), SemInput, Sem, emptyLiteral+                          , sortSem+                          )+import NLP.GenI.Tag ( TagElem(..), TagItem(..), setTidnums )+import NLP.GenI.TreeSchema ( Ptype(Initial), GNode, root, gup, gdown, rootUpd)++-- ----------------------------------------------------------------------+-- Interface+-- ----------------------------------------------------------------------++-- | intermediate auts, seed aut, final aut, potentially modified sem+data PolResult = PolResult { prIntermediate :: [AutDebug]+                           , prInitial      :: PolAut+                           , prFinal        :: PolAut+                           , prSem          :: Sem }+type AutDebug  = (PolarityKey, PolAut, PolAut)++-- | Constructs a polarity automaton.  For debugging purposes, it returns+--   all the intermediate automata produced by the construction algorithm.+buildAutomaton :: Set.Set PolarityAttr -- ^ polarities to detect (eg. "cat")+               -> FeatStruct GeniVal   -- ^ root features to compensate for+               -> PolMap               -- ^ explicit extra polarities+               -> SemInput             -- ^ input semantics+               -> [TagElem]            -- ^ lexical selection+               -> PolResult+buildAutomaton polarityAttrs rootFeat extrapol (tsem,tres,_) candRaw =+  let -- root categories, index constraints, and external polarities+      rcatPol :: PolMap+      rcatPol = detectRootCompensation polarityAttrs rootFeat+      -- index constraints on candidate trees+      detect      = detectIdxConstraints tres+      constrain t = t { tpolarities = Map.unionWith (!+!) p r+                      } --, tinterface  = [] }+                   where p  = tpolarities t+                         r  = detect . tinterface $ t+      candRest  = map constrain candRaw+      inputRest = declareIdxConstraints tres+      -- polarity detection +      cand1   = map (detectPols polarityAttrs) candRest+      extras1 = Map.unionsWith (!+!) [ extrapol, inputRest, rcatPol ]+      ks1     = polarityKeys cand1 Map.empty+      -- expanding unconstrained polarities+      tconvert t = t { tpolarities = convertUnconstrainedPolarities ks1 (tpolarities t) }+      cand    = map tconvert cand1+      extras  = convertUnconstrainedPolarities ks1 extras1+      ks      = polarityKeys cand extras+      -- building the automaton+  in makePolAut cand tsem extras ks++makePolAut :: [TagElem] -> Sem -> PolMap -> [PolarityKey] -> PolResult+makePolAut candsRaw tsemRaw extraPol ks =+ let -- perform index counting+     (tsem, cands') = fixPronouns (tsemRaw,candsRaw)+     cands = setTidnums cands'+     -- sorted semantics (for more efficient construction)+     sortedsem = sortSemByFreq tsem cands +     -- the seed automaton+     smap = buildColumns cands sortedsem +     seed = buildSeedAut smap  sortedsem+     -- building and remembering the automata +     build k xs = (k,aut,prune aut):xs+       where aut   = buildPolAut k initK (thd3 $ head xs)+             initK = Map.findWithDefault (ival 0) k extraPol+     res = foldr build [(PolarityKeyStr "(seed)",seed,prune seed)] ks+ in PolResult { prIntermediate = reverse res+              , prInitial      = seed+              , prFinal        = thd3 $ head res+              , prSem          = tsem }++-- ====================================================================+-- Polarity automaton+-- ====================================================================++-- | Note: this is not the same function as 'NLP.GenI.Tags.mapBySem'!+-- The fact that we+-- preserve the order of the input semantics is important for our handling+-- of multi-literal semantics and for semantic frequency sorting.+buildColumns :: (TagItem t) => [t]+             -> Sem+             -> Map.Map (Literal GeniVal) [t]+buildColumns cands [] = +  Map.singleton emptyLiteral e+  where e = filter (null.tgSemantics) cands++buildColumns cands (l:ls) = +  let matchfn t = l `elem` tgSemantics t+      (match, cands2) = partition matchfn cands+      next = buildColumns cands2 ls+  in Map.insert l match next++-- ----------------------------------------------------------------------+-- Initial Automaton+-- ----------------------------------------------------------------------++buildSeedAut :: SemMap -> Sem -> PolAut+buildSeedAut cands tsem = +  let start = polstart []+      hasZero (x,y) = x <= 0 && y >= 0+      isFinal (PolSt c _ pols) = +        c == length tsem && all hasZero pols+      initAut = NFA +        { startSt = start+        , isFinalSt = Just isFinal+        , finalStList = []+        , states  = [[start]]+        , transitions = Map.empty }+  in nubAut $ buildSeedAut' cands tsem 1 initAut++-- for each literal...+buildSeedAut' :: SemMap -> Sem -> Int -> PolAut -> PolAut +buildSeedAut' _ [] _ aut = aut +buildSeedAut' cands (l:ls) i aut = +  let -- previously created candidates +      prev   = head $ states aut+      -- candidates that match the target semantics+      tcands = Map.findWithDefault [] l cands+      -- create the next batch of states+      fn st ap             = buildSeedAutHelper tcands l i st ap+      (newAut,newStates)   = foldr fn (aut,[]) prev+      next                 = nub newStates : states aut+      -- recursive step to the next literal+  in buildSeedAut' cands ls (i+1) (newAut { states = next })++-- for each candidate corresponding to literal l...+buildSeedAutHelper :: [TagElem]+                   -> Literal GeniVal+                   -> Int+                   -> PolState+                   -> (PolAut,[PolState])+                   -> (PolAut,[PolState])+buildSeedAutHelper cs l i st (aut,prev) =+  let -- get the extra semantics from the last state+      (PolSt _ ex1 _) = st+      -- candidates that match the target semantics and which+      -- do not overlap the extra baggage semantics+      tcand = [ Just t | t <- cs+              , isEmptyIntersect ex1 (tsemantics t) ]+      -- add the transitions out of the current state +      addT tr (a,n) = (addTrans a st tr st2, st2:n)+        where +         st2 = PolSt i (delete l $ ex1 ++ ex2) []+         ex2 = case tr of +               Nothing  -> [] +               Just tr_ -> tsemantics tr_+  in if (l `elem` ex1) +     then addT Nothing (aut,prev)+     else foldr addT   (aut,prev) tcand ++-- ----------------------------------------------------------------------+-- Construction+-- ----------------------------------------------------------------------++buildPolAut :: PolarityKey -> Interval -> PolAut -> PolAut+buildPolAut k initK skelAut =+  let concatPol p (PolSt pr b pol) = PolSt pr b (p:pol)+      newStart = concatPol initK $ startSt skelAut+      --+      initAut  = skelAut +        { startSt = newStart+        , states  = [[newStart]]+        , transitions = Map.empty }+      -- cand' = observe "candidate map" cand +  in nubAut $ buildPolAut' k (transitions skelAut) initAut ++{-+Our helper function looks at a single state in the skeleton automaton+and at one of the states in the new automaton which correspond to it.+We use the transitions from the old automaton to determine which states+to construct.  Note: there can be more than one state in the automaton+which corresponds to a state in the old automaton.  This is because we+are looking at a different polarity key, so that whereas two candidates+automaton may transition to the same state in the old automaton, their+polarity effects for the new key will make them diverge in the new+automaton.  +-}++buildPolAut' :: PolarityKey -> PolTransFn -> PolAut -> PolAut+-- for each literal... (this is implicit in the automaton state grouping)+buildPolAut' fk skeleton aut = +  let -- previously created candidates +      prev = head $ states aut +      -- create the next batch of states+      fn st ap            = buildPolAutHelper fk skeleton st ap+      (newAut,newStates)  = foldr fn (aut,Set.empty) prev+      next                = Set.toList newStates : states aut+      -- recursive step to the next literal+  in if Set.null newStates+     then aut+     else buildPolAut' fk skeleton (newAut { states = next })++-- given a previously created state...+buildPolAutHelper :: PolarityKey -> PolTransFn -> PolState -> (PolAut,Set.Set PolState) -> (PolAut,Set.Set PolState)+buildPolAutHelper fk skeleton st (aut,prev) =+  let -- reconstruct the skeleton state used to build st +      PolSt pr ex (po1:skelpo1) = st+      skelSt = PolSt pr ex skelpo1+      -- for each transition out of the current state+      -- nb: a transition is (next state, [labels to that state])+      trans = Map.toList $ Map.findWithDefault Map.empty skelSt skeleton+      result = foldr addT (aut,prev) trans+      -- . for each label to the next state st2+      addT (oldSt2,trs) (a,n) = foldr (addTS oldSt2) (a,n) trs+      -- .. calculate a new state and add a transition to it+      addTS skel2 tr (a,n) = (addTrans a st tr st2, Set.insert st2 n)+        where st2 = newSt tr skel2+      --+      newSt :: Maybe TagElem -> PolState -> PolState+      newSt t skel2 = PolSt pr2 ex2 (po2:skelPo2)+        where +         PolSt pr2 ex2 skelPo2 = skel2 +         po2 = po1 !+! Map.findWithDefault (ival 0) fk pol+         pol = case t of Nothing -> Map.empty +                         Just t2 -> tpolarities t2+  in result ++-- ----------------------------------------------------------------------+-- Pruning+-- ----------------------------------------------------------------------++{-|+The pruning algorithm takes as arguments a list of states to process.+Among these, any state which does not have outgoing transitions is+placed on the blacklist.  We remove all transitions to the blacklist and+all states that only transition to the blacklist, and then we repeat+pruning, with a next batch of states.++Finally, we return the pruned automaton.  Note: in order for this to+work, it is essential that the final states are *not* included in the+list of states to process.+-}+prune :: PolAut -> PolAut+prune aut = +  let theStates   = states aut+      final       = finalSt aut+      -- (remember that states is a list of lists) +      lastStates  = head theStates +      nextStates  = tail theStates +      nonFinal    = (lastStates \\ final)+      -- the helper function will rebuild the state list+      firstAut    = aut { states = [] }+      pruned      = prune' (nonFinal:nextStates) firstAut +      -- re-add the final state!+      statesPruned = states pruned+      headPruned   = head statesPruned+      tailPruned   = tail statesPruned+  in if (null theStates) +     then aut+     else pruned { states = (headPruned ++ final) : tailPruned } ++prune' :: [[PolState]] -> PolAut -> PolAut+prune' [] oldAut = oldAut { states = reverse $ states oldAut }+prune' (sts:next) oldAut = +  let -- calculate the blacklist+      oldT  = transitions oldAut+      oldSt = states oldAut+      transFrom st = Map.lookup st oldT+      blacklist    = filter (isNothing.transFrom) sts+      -- given a st: filter out all transitions to the blacklist+      allTrans  = Map.toList $ transitions oldAut+      -- delete all transitions to the blacklist+      miniTrim = Map.filterWithKey (\k _ -> not (k `elem` blacklist))+      -- extra cleanup: delete from map states that only transition to the blacklist+      trim = Map.filterWithKey (\k m -> not (k `elem` blacklist || Map.null m))+      -- execute the kill and miniKill filters+      newT = trim $ Map.fromList [ (st2, miniTrim m) | (st2,m) <- allTrans ]+      -- new list of states and new automaton+      newSts = sts \\ blacklist+      newAut = oldAut { transitions = newT,+                        states = newSts : oldSt }+      {- +      -- debugging code+      debugstr  = "blacklist: [\n" ++ debugstr' ++ "]"+      debugstr' = concat $ intersperse "\n" $ map showSt blacklist+      showSt (PolSt pr ex po) = showPr pr ++ showEx ex ++ showPo po+      showPr (_,pr,_) = pr ++ " " +      showPo po = concat $ intersperse "," $ map show po+      showEx ex = if (null ex) then "" else (showSem ex)+      -}+      -- recursive step+  in if null blacklist+     then oldAut { states = (reverse oldSt) ++ (sts:next) }+     else prune' next newAut ++-- ====================================================================+-- Zero-literal semantics+-- ====================================================================++type PredLite = (String,[GeniVal]) -- handle is head of arg list +type SemWeightMap = Map.Map PredLite SemPols++-- | Returns a modified input semantics and lexical selection in which pronouns+--   are properly accounted for.+fixPronouns :: (Sem,[TagElem]) -> (Sem,[TagElem])+fixPronouns (tsem,cands) = +  let -- part 1 (for each literal get smallest charge for each idx)+      getpols :: TagElem -> [ (PredLite,SemPols) ]+      getpols x = zip [ (prettyStr p, h:as) | Literal h p as <- tsemantics x ] (tsempols x)+      sempols :: [ (PredLite,SemPols) ]+      sempols = concatMap getpols cands+      usagemap :: SemWeightMap +      usagemap = Map.fromListWith (zipWith min) sempols+      -- part 2 (cancel sem polarities)+      chargemap :: Map.Map GeniVal Int -- index to charge +      chargemap =  Map.fromListWith (+) $ concatMap clump $ Map.toList usagemap+        where clump ((_,is),ps) = zip is ps+      -- part 3 (adding extra semantics)+      indices = concatMap fn (Map.toList chargemap) +        where fn (i,c) = replicate (negate c) i+      -- the extra columns +      extraSem = map indexLiteral indices+      tsem2    = sortSem (tsem ++ extraSem)+      -- zero-literal semantic items to realise the extra columns +      zlit = filter (null.tsemantics) cands+      cands2 = (cands \\ zlit) ++ concatMap fn indices+        where fn i = map (tweak i) zlit+              tweak i x = assignIndex i $ x { tsemantics = [indexLiteral i] }+      -- part 4 (insert excess pronouns in tree sem)+      comparefn :: GeniVal -> Int -> Int -> [GeniVal]+      comparefn i ct cm = if cm < ct then extra else []+        where maxNeeded = Map.findWithDefault 0 i chargemap -- cap the number added+              extra = replicate (min (negate maxNeeded) (ct - cm)) i+      comparePron :: (PredLite,SemPols) -> [GeniVal]+      comparePron (lit,c1) = concat $ zipWith3 comparefn idxs c1 c2+        where idxs = snd lit+              c2   = Map.findWithDefault [] lit usagemap+      addextra :: TagElem -> TagElem+      addextra c = c { tsemantics = sortSem (sem ++ extra) }+        where sem   = tsemantics c+              extra = map indexLiteral $ concatMap comparePron (getpols c)+      cands3 = map addextra cands2+  in (tsem2, cands3)++-- | Builds a fake semantic predicate that the index counting mechanism uses to+--   represent extra columns.+indexLiteral :: GeniVal -> Literal GeniVal+indexLiteral x = Literal x mkGAnon []++-- Returns True if the given literal was introduced by the index counting mechanism+isExtraCol :: Literal GeniVal -> Bool+isExtraCol (Literal _ p []) = isAnon p+isExtraCol _                = False++-- | 'assignIndex' is a useful way to restrict the behaviour of+-- null semantic items like pronouns using the information generated by+-- the index counting mechanism.  The problem with null semantic items +-- is that their indices are not set, which means that they could+-- potentially combine with any other tree.  To make things more +-- efficient, we can set the index of these items and thus reduce the+-- number of spurious combinations.  +-- +-- Notes+--+-- * These combinations could produce false results if the+--   input has to use multiple pronouns.  For example, if you wanted to say+--   something like “John promises Mary to convince Paul to give her+--   his book”, these combinations could instead produce “give him+--   *her* book“.+--+-- * This function works by FS unification on the root node of the+--   tree with the *[idx:i]*.  If unification is not possible, +--   we simply return the tree as is.+--+-- * This function renames the tree by appending the index to its name+assignIndex :: GeniVal -> TagElem -> TagElem +assignIndex i te =+  let idxfs = [ AvPair __idx__ i ]+      oldt  = ttree te+      oldr  = root oldt+      tfup  = gup oldr+      --+  in case unifyFeat tfup idxfs of+     Nothing          -> te+     Just (gup2, sub) -> replace sub $ te { ttree = newt }+       where newt = rootUpd oldt $ oldr { gup = gup2 }++-- ====================================================================+-- Further optimisations+-- ====================================================================++-- Index constraints +-- -----------------+detectIdxConstraints :: Flist GeniVal -> Flist GeniVal -> PolMap+detectIdxConstraints cs interface =+  let matches  = intersect cs interface+      matchStr = map idxConstraintKey matches+  in Map.fromList $ zip matchStr ((repeat.ival) 1)++declareIdxConstraints :: Flist GeniVal -> PolMap+declareIdxConstraints = Map.fromList . (map declare) where+   declare c = (idxConstraintKey c, minusone)+   minusone = ival (-1)++-- TODO: test that index constraints come first+idxConstraintKey :: AvPair GeniVal -> PolarityKey+idxConstraintKey = PolarityKeyStr . ("." <>) . pretty++-- Automatic polarity detection+-- ----------------------------+suggestPolFeatures :: [TagElem] -> [Text]+suggestPolFeatures tes =+  let -- only initial trees need be counted; in aux trees, the+      -- root node is implicitly canceled by the foot node+      rfeats, sfeats :: [Flist GeniVal]+      rfeats = map (gdown.root.ttree) $ filter (\t -> ttype t == Initial) tes+      sfeats = [ concat s | s <- map substTops tes, (not.null) s ]+      --+      attrs :: Flist GeniVal -> [Text]+      attrs avs = [ a | AvPair a v <- avs, isJust (gConstraints v) ]+      theAttributes = map attrs $ rfeats ++ sfeats+  in if null theAttributes then [] else foldr1 intersect theAttributes++-- FIXME: temporary HACKY code - delete me as soon as possible (written+-- 2006-03-30+--+-- only initial trees need be counted; in aux trees, the+-- root node is implicitly canceled by the foot node+detectSansIdx :: [TagElem] -> [TagElem]+detectSansIdx =+  let rfeats t = (gdown.root.ttree) t+      feats  t | ttype t == Initial = concat $ rfeats t : substTops t+      feats  t = concat $ substTops t+      attrs avs = [ a | AvPair a v <- avs, isJust (gConstraints v) ]+      hasIdx t = __idx__ `elem` (attrs.feats $ t) || (ttype t /= Initial && (null $ substTops t))+  in filter (not.hasIdx)++detectPols :: Set.Set PolarityAttr -> TagElem -> TagElem+detectPols attrs t =+  t { tpolarities = addPols (detectPolsH attrs t) (tpolarities t) }++-- Chart sharing+-- -------------++-- | Given a list of paths (i.e. a list of list of trees)+--   return a list of trees such that each tree is annotated with the paths it+--   belongs to.+detectPolPaths :: [[TagElem]] -> [(TagElem,BitVector)]+detectPolPaths paths = +  let pathFM     = detectPolPaths' Map.empty 0 paths+      lookupTr k = Map.findWithDefault 0 k pathFM+  in map (\k -> (k, lookupTr k)) $ Map.keys pathFM++type PolPathMap = Map.Map TagElem BitVector+detectPolPaths' :: PolPathMap -> Int -> [[TagElem]] -> PolPathMap  ++detectPolPaths' accFM _ [] = accFM+detectPolPaths' accFM counter (path:ps) = +  let currentBits = shiftL 1 counter -- shift counter times the 1 bit+      fn f []     = f+      fn f (t:ts) = fn (Map.insertWith (.|.) t currentBits f) ts +      newFM       = fn accFM path+  in detectPolPaths' newFM (counter+1) ps++-- | Render the list of polarity automaton paths as a string+prettyPolPaths :: BitVector -> Text+prettyPolPaths paths =+    T.intercalate ", " $ map pretty pathlist+  where+    pathlist = prettyPolPaths' paths 1++prettyPolPaths' :: BitVector -> Int -> [Int] +prettyPolPaths' 0 _ = []+prettyPolPaths' bv counter = +  if b then (counter:next) else next+  where b = testBit bv 0+        next = prettyPolPaths' (shiftR bv 1) (counter + 1)++-- Semantic sorting+-- ----------------++sortSemByFreq :: Sem -> [TagElem] -> Sem+sortSemByFreq tsem cands = +  let counts = map lenfn tsem +      lenfn l = length $ filter fn cands +                where fn x = l `elem` (tsemantics x)+      -- note: we introduce an extra hack to push+      -- index-counted extra columns to the end; just for UI reasons+      sortfn a b +        | isX a && isX b = compare (snd a) (snd b)+        | isX a          = GT+        | isX b          = LT+        | otherwise      = compare (snd a) (snd b)+        where isX = isExtraCol.fst +      sorted = sortBy sortfn $ zip tsem counts +  in (fst.unzip) sorted ++-- ----------------------------------------------------------------------+-- Types+-- ----------------------------------------------------------------------++-- Polarity NFA++data PolState = PolSt Int [Literal GeniVal] [(Int,Int)]+                -- ^ position in the input semantics, extra semantics, +                --   polarity interval+     deriving (Eq)+type PolTrans = TagElem+type PolAut   = NFA PolState PolTrans+type PolTransFn = Map.Map PolState (Map.Map PolState [Maybe PolTrans])++instance Show PolState+  where show (PolSt pr ex po) = show pr ++ " " ++ prettyStr ex ++ show po+-- showPred pr ++ " " ++ showSem ex ++ show po++instance Ord PolState where+  compare (PolSt pr1 ex1 po1) (PolSt pr2 ex2 po2) = +    let prC   = compare pr1 pr2+        expoC = compare (ex1,po1) (ex2,po2)+    in if (prC == EQ) then expoC else prC++-- We include also some fake states which are useful for general+-- housekeeping during the main algortihms.+fakestate :: Int -> [Interval] -> PolState+fakestate s pol = PolSt s [] pol --PolSt (0, s, [""]) [] pol++-- | an initial state for polarity automata+polstart :: [Interval] -> PolState+polstart pol = fakestate 0 pol -- fakestate "START" pol
− src/NLP/GenI/Polarity.lhs
@@ -1,1206 +0,0 @@-% GenI surface realiser-% Copyright (C) 2009 Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.--\chapter{Polarity Optimisation}-\label{cha:Polarity}--We introduce a notion of polarities as a means of pre-detecting-incompatibilities between candidate trees for different propositions.-This optimisation is inserted between candidate selection -(section \ref{sec:candidate_selection})-and chart generation.  The input to this optimisation is the-\jargon{target semantics} and the corresponding \jargon{candidate-  trees}.--This whole optimisation is based on adding polarities to the grammar.-We have a set of strings which we call \jargon{polarity keys}, and some-positive or negative integers which we call \jargon{charges}.  Each tree-in the grammar may assign a charge to some number of polarity keys.  For-example, here is a simple grammar that uses the polarity keys n and v.--\begin{tabular}{|l|l|}-\hline-tree & polarity effects \\-\hline-s(n$\downarrow$, v$\downarrow$, n$\downarrow$) & -2n -v\\-v(hates) & +v\\-n(mary) & +n\\-n(john) & +n\\-\hline-\end{tabular}--For now, these annotations are done by hand, and are based on syntactic-criteria (substitution and root node categories) but one could envisage-alternate criteria or an eventual means of automating the process.  --The basic idea is to use the polarity keys to determine which subsets of-candidate trees are incompatible with each other and rule them out.  We-construct a finite state automaton which uses polarity keys to-pre-calculate the compatibility of sets of trees.  At the end of the-optimisation, we are left with an automaton, each path of which is a-potentially compatible set of trees.  We then preform surface-realisation seperately, treating each path as a set of candidate trees.--\emph{Important note}: one thing that may be confusing in this chapter-is that we refer to polarities (charges) as single integers, e.g, $-2n$.-In reality, to account for weird stuff like atomic disjunction, we do-not use simple integers, but polarities intervals, so more something -like $(-2,-2)n$!  But for the most part, the intervals are zero length,-and you can just think of $-2n$ as shorthand for $(-2,-2)n$.--\begin{code}-module NLP.GenI.Polarity(-                -- * Entry point-                PolAut, PolState(PolSt), AutDebug, PolResult,-                buildAutomaton,--                -- * Inner stuff (exported for debugging?)-                makePolAut,-                fixPronouns,-                detectSansIdx, detectPolFeatures, detectPols, detectPolPaths,-                declareIdxConstraints, detectIdxConstraints,-                showLite, showLitePm, showPolPaths, showPolPaths',--                -- re-exported from Automaton-                automatonPaths, finalSt,-                NFA(states, transitions),-                )-where-\end{code}--\begin{code}-import Data.Bits-import qualified Data.Set as Set-import qualified Data.Map as Map-import Data.List-import Data.Maybe (isNothing, isJust)-import Data.Tree (flatten)-import qualified Data.Set as Set--import NLP.GenI.Automaton-import NLP.GenI.Btypes(Pred, SemInput, Sem, Flist, AvPair(..), showAv,-              GeniVal(..), fromGConst, isConst,-              replace,-              emptyPred, Ptype(Initial), -              showFlist, showSem, sortSem,-              GNode, root, gup, gdown, gtype, GType(Subs),-              SemPols, unify, unifyFeat, rootUpd)-import NLP.GenI.General(-    BitVector, isEmptyIntersect, thd3,-    Interval, ival, (!+!), showInterval)-import NLP.GenI.PolarityTypes-import NLP.GenI.Tags(TagElem(..), TagItem(..), setTidnums)-\end{code}--\section{Interface}--\begin{code}--- | intermediate auts, seed aut, final aut, potentially modified sem-type PolResult = ([AutDebug], PolAut, PolAut, Sem)-type AutDebug  = (PolarityKey, PolAut, PolAut)---- | Constructs a polarity automaton.  For debugging purposes, it returns---   all the intermediate automata produced by the construction algorithm.-buildAutomaton :: Set.Set PolarityAttr -- ^ polarities to detect-               -> Flist                -- ^ root features to compensate for-               -> PolMap               -- ^ explicit extra polarities-               -> SemInput             -- ^ input semantics-               -> [TagElem]            -- ^ lexical selection-               -> PolResult-buildAutomaton polarityAttrs rootFeat extrapol (tsem,tres,_) candRaw =-  let -- root categories, index constraints, and external polarities-      rcatPol :: Map.Map PolarityKey Interval-      rcatPol = Map.fromList . pdJusts-              $ map (\v -> detectPolarityForAttr (-1) (pAttr v) rootFeat)-              $ Set.toList polarityAttrs-      pAttr p@(SimplePolarityAttr _)       = spkAtt p-      pAttr p@(RestrictedPolarityAttr _ _) = rpkAtt p-      ---      allExtraPols = Map.unionsWith (!+!) [ extrapol, inputRest, rcatPol ]-      -- index constraints on candidate trees-      detect      = detectIdxConstraints tres-      constrain t = t { tpolarities = Map.unionWith (!+!) p r-                      } --, tinterface  = [] }-                   where p  = tpolarities t-                         r  = detect . tinterface $ t-      candRest  = map constrain candRaw-      inputRest = declareIdxConstraints tres-      -- polarity detection -      cand = detectPols polarityAttrs candRest-      -- building the automaton-  in makePolAut cand tsem allExtraPols-\end{code}--\section{The automaton itself - outline}-\label{polarity:overview}--We start with the controller function (the general architecture) and-detail the individual steps in the following sections.  The basic-architecture is as follows:--\begin{enumerate}-\item Build a seed automaton (section \ref{sec:seed_automaton}).-\item For each polarity key, elaborate the -      automaton with the polarity information for that key-      (section \ref{sec:automaton_construction}) and minimise-      the automaton (section \ref{sec:automaton_pruning}).-\end{enumerate}--The above process can be thought of as a more efficient way of-constructing an automaton for each polarity key, minimising said-automaton, and then taking their intersection.  In any case, -we return everything a tuple with (1) a list of the automota that-were created (2) the final automaton (3) a possibly modified-input semantics.  The first item is only neccesary for debugging; only-the last two are important.--Note: -\begin{itemize}-\item the \fnparam{extraPol} argument is a map containing any initial-  values for polarity keys.  This is useful to impose external filters-  like ``I only want expressions where the object is topicalised''.  -\item to recuperate something useful from these automaton, it might-  be helpful to call \fnref{automatonPaths} on it.-\end{itemize}--\begin{code}-makePolAut :: [TagElem] -> Sem -> PolMap -> PolResult-makePolAut candsRaw tsemRaw extraPol =- let -- polarity items-     ksCands = concatMap (Map.keys . tpolarities) cands-     ksExtra = Map.keys extraPol-     ks      = sortBy (flip compare) $ nub $ ksCands ++ ksExtra-     -- perform index counting-     (tsem, cands') = fixPronouns (tsemRaw,candsRaw)-     cands = setTidnums cands'-     -- sorted semantics (for more efficient construction)-     sortedsem = sortSemByFreq tsem cands -     -- the seed automaton-     smap = buildColumns cands sortedsem -     seed = buildSeedAut smap  sortedsem-     -- building and remembering the automata -     build k xs = (k,aut,prune aut):xs-       where aut   = buildPolAut k initK (thd3 $ head xs)-             initK = Map.findWithDefault (ival 0) k extraPol-     res = foldr build [(PolarityKey "(seed)",seed,prune seed)] ks- in (reverse res, seed, thd3 $ head res, tsem)-\end{code}--% ====================================================================-\section{Polarity automaton}-\label{sec:polarity_automaton}-% ====================================================================--We construct a finite state automaton for each polarity key that is in-the set of trees. It helps to imagine a table where each column-corresponds to a single proposition.  --\begin{center}-\begin{tabular}{|c|c|c|}-\hline-\semexpr{gift(g)} & \semexpr{cost(g,x)}    & \semexpr{high(x)} \\-\hline-\natlang{the gift} \color{blue}{+1np} & -\natlang{the cost of}  & -\natlang{is high} \color{red}{-1np} \\-%-\natlang{the present}    \color{blue}{+1np} & -\natlang{costs} \color{red}{-1np}    & -\natlang{a lot}    \\-%-&& \natlang{much} \\-\hline-\end{tabular}-\end{center}--Each column (proposition) has a different number of cells which-corresponds to the lexical ambiguity for that proposition, more-concretely, the number of candidate trees for that proposition.  The-\jargon{polarity automaton} describes the different ways we can traverse-the table from column to column, choosing a cell to pass through at each-step and accumulating polarity along the way.  Each state represents the-polarity at a column and each transition represents the tree we chose to-get there.  All transitions from one columns $i$ to the next $i+1$ that-lead to the same accumulated polarity lead to the same state.  --% -----------------------------------------------------------------------\subsection{Columns}-% ------------------------------------------------------------------------We build the columns for the polarity automaton as follows.  Given a-input semantics \texttt{sem} and a list of trees \texttt{cands}, we-group the trees by the first literal of sem that is part of their tree-semantics.  --Note: this is not the same function as Tags.mapBySem! The fact that we-preserve the order of the input semantics is important for our handling-of multi-literal semantics and for semantic frequency sorting.--\begin{code}-buildColumns :: (TagItem t) => [t] -> Sem -> Map.Map Pred [t] -buildColumns cands [] = -  Map.singleton emptyPred e -  where e = filter (null.tgSemantics) cands--buildColumns cands (l:ls) = -  let matchfn t = l `elem` tgSemantics t-      (match, cands2) = partition matchfn cands-      next = buildColumns cands2 ls-  in Map.insert l match next-\end{code}--% -----------------------------------------------------------------------\subsection{Initial Automaton}-\label{sec:seed_automaton}-% ------------------------------------------------------------------------We first construct a relatively trivial polarity automaton without any-polarity effects.  Each state except the start state corresponds-to a literal in the target semantics, and the transitions to a state -consist of the trees whose semantics is subsumed by that literal.  --\begin{code}-buildSeedAut :: SemMap -> Sem -> PolAut-buildSeedAut cands tsem = -  let start = polstart []-      hasZero (x,y) = x <= 0 && y >= 0-      isFinal (PolSt c _ pols) = -        c == length tsem && all hasZero pols-      initAut = NFA -        { startSt = start-        , isFinalSt = Just isFinal-        , finalStList = []-        , states  = [[start]]-        , transitions = Map.empty }-  in nubAut $ buildSeedAut' cands tsem 1 initAut---- for each literal...-buildSeedAut' :: SemMap -> Sem -> Int -> PolAut -> PolAut -buildSeedAut' _ [] _ aut = aut -buildSeedAut' cands (l:ls) i aut = -  let -- previously created candidates -      prev   = head $ states aut-      -- candidates that match the target semantics-      tcands = Map.findWithDefault [] l cands-      -- create the next batch of states-      fn st ap             = buildSeedAutHelper tcands l i st ap-      (newAut,newStates)   = foldr fn (aut,[]) prev-      next                 = nub newStates : states aut-      -- recursive step to the next literal-  in buildSeedAut' cands ls (i+1) (newAut { states = next })---- for each candidate corresponding to literal l...-buildSeedAutHelper :: [TagElem] -> Pred -> Int -> PolState -> (PolAut,[PolState]) -> (PolAut,[PolState])-buildSeedAutHelper cs l i st (aut,prev) =-  let -- get the extra semantics from the last state-      (PolSt _ ex1 _) = st-      -- candidates that match the target semantics and which-      -- do not overlap the extra baggage semantics-      tcand = [ Just t | t <- cs-              , isEmptyIntersect ex1 (tsemantics t) ]-      -- add the transitions out of the current state -      addT tr (a,n) = (addTrans a st tr st2, st2:n)-        where -         st2 = PolSt i (delete l $ ex1 ++ ex2) []-         ex2 = case tr of -               Nothing  -> [] -               Just tr_ -> tsemantics tr_-  in if (l `elem` ex1) -     then addT Nothing (aut,prev)-     else foldr addT   (aut,prev) tcand -\end{code}--% -----------------------------------------------------------------------\subsection{Construction}-\label{sec:automaton_construction}-\label{sec:automaton_intersection}-% ------------------------------------------------------------------------The goal is to construct a polarity automaton which accounts for a-given polarity key $k$.  The basic idea is that given -literals $p_1..p_n$ in the target semantics, we create a start state,-calculate the states/transitions to $p_1$ and succesively calculate-the states/transitions from proposition $p_x$ to $p_{x+1}$ for all-$1 < x < n$. --The ultimate goal is to construct an automaton that accounts for -multiple polarity keys.  The simplest approach would be to -calculate a seperate automaton for each key, prune them all and -then intersect the pruned automaton together, but we can do much -better than that.  Since the pruned automata are generally much-smaller in size, we perform an iterative intersection by using -a previously pruned automaton as the skeleton for the current -automaton.  This is why we don't pass any literals or candidates-to the construction step; it takes them directly from the previous-automaton.  See also section \ref{sec:seed_automaton} for the seed -automaton that you can use when there is no ``previous automaton''.--\begin{code}-buildPolAut :: PolarityKey -> Interval -> PolAut -> PolAut-buildPolAut k initK skelAut =-  let concatPol p (PolSt pr b pol) = PolSt pr b (p:pol)-      newStart = concatPol initK $ startSt skelAut-      ---      initAut  = skelAut -        { startSt = newStart-        , states  = [[newStart]]-        , transitions = Map.empty }-      -- cand' = observe "candidate map" cand -  in nubAut $ buildPolAut' k (transitions skelAut) initAut -\end{code}--Our helper function looks at a single state in the skeleton automaton-and at one of the states in the new automaton which correspond to it.-We use the transitions from the old automaton to determine which states-to construct.  Note: there can be more than one state in the automaton-which corresponds to a state in the old automaton.  This is because we-are looking at a different polarity key, so that whereas two candidates-automaton may transition to the same state in the old automaton, their-polarity effects for the new key will make them diverge in the new-automaton.  --\begin{code}-buildPolAut' :: PolarityKey -> PolTransFn -> PolAut -> PolAut--- for each literal... (this is implicit in the automaton state grouping)-buildPolAut' fk skeleton aut = -  let -- previously created candidates -      prev = head $ states aut -      -- create the next batch of states-      fn st ap            = buildPolAutHelper fk skeleton st ap-      (newAut,newStates)  = foldr fn (aut,Set.empty) prev-      next                = Set.toList newStates : states aut-      -- recursive step to the next literal-  in if Set.null newStates-     then aut-     else buildPolAut' fk skeleton (newAut { states = next })---- given a previously created state...-buildPolAutHelper :: PolarityKey -> PolTransFn -> PolState -> (PolAut,Set.Set PolState) -> (PolAut,Set.Set PolState)-buildPolAutHelper fk skeleton st (aut,prev) =-  let -- reconstruct the skeleton state used to build st -      PolSt pr ex (po1:skelpo1) = st-      skelSt = PolSt pr ex skelpo1-      -- for each transition out of the current state-      -- nb: a transition is (next state, [labels to that state])-      trans = Map.toList $ Map.findWithDefault Map.empty skelSt skeleton-      result = foldr addT (aut,prev) trans-      -- . for each label to the next state st2-      addT (oldSt2,trs) (a,n) = foldr (addTS oldSt2) (a,n) trs-      -- .. calculate a new state and add a transition to it-      addTS skel2 tr (a,n) = (addTrans a st tr st2, Set.insert st2 n)-        where st2 = newSt tr skel2-      ---      newSt :: Maybe TagElem -> PolState -> PolState-      newSt t skel2 = PolSt pr2 ex2 (po2:skelPo2)-        where -         PolSt pr2 ex2 skelPo2 = skel2 -         po2 = po1 !+! Map.findWithDefault (ival 0) fk pol-         pol = case t of Nothing -> Map.empty -                         Just t2 -> tpolarities t2-  in result -\end{code}--% -----------------------------------------------------------------------\subsection{Pruning}-\label{sec:automaton_pruning}-% ------------------------------------------------------------------------Any path through the automaton which does not lead to final-polarity of zero sum can now be eliminated.  We do this by stepping-recursively backwards from the final states: --\begin{code}-prune :: PolAut -> PolAut-prune aut = -  let theStates   = states aut-      final       = finalSt aut-      -- (remember that states is a list of lists) -      lastStates  = head theStates -      nextStates  = tail theStates -      nonFinal    = (lastStates \\ final)-      -- the helper function will rebuild the state list-      firstAut    = aut { states = [] }-      pruned      = prune' (nonFinal:nextStates) firstAut -      -- re-add the final state!-      statesPruned = states pruned-      headPruned   = head statesPruned-      tailPruned   = tail statesPruned-  in if (null theStates) -     then aut-     else pruned { states = (headPruned ++ final) : tailPruned } -\end{code}--The pruning algorithm takes as arguments a list of states to process.-Among these, any state which does not have outgoing transitions is-placed on the blacklist.  We remove all transitions to the blacklist and-all states that only transition to the blacklist, and then we repeat-pruning, with a next batch of states.  --Finally, we return the pruned automaton.  Note: in order for this to-work, it is essential that the final states are *not* included in the-list of states to process.--\begin{code}-prune' :: [[PolState]] -> PolAut -> PolAut-prune' [] oldAut = oldAut { states = reverse $ states oldAut }-prune' (sts:next) oldAut = -  let -- calculate the blacklist-      oldT  = transitions oldAut-      oldSt = states oldAut-      transFrom st = Map.lookup st oldT-      blacklist    = filter (isNothing.transFrom) sts-      -- given a st: filter out all transitions to the blacklist-      allTrans  = Map.toList $ transitions oldAut-      -- delete all transitions to the blacklist-      miniTrim = Map.filterWithKey (\k _ -> not (k `elem` blacklist))-      -- extra cleanup: delete from map states that only transition to the blacklist-      trim = Map.filterWithKey (\k m -> not (k `elem` blacklist || Map.null m))-      -- execute the kill and miniKill filters-      newT = trim $ Map.fromList [ (st2, miniTrim m) | (st2,m) <- allTrans ]-      -- new list of states and new automaton-      newSts = sts \\ blacklist-      newAut = oldAut { transitions = newT,-                        states = newSts : oldSt }-      {- -      -- debugging code-      debugstr  = "blacklist: [\n" ++ debugstr' ++ "]"-      debugstr' = concat $ intersperse "\n" $ map showSt blacklist-      showSt (PolSt pr ex po) = showPr pr ++ showEx ex ++ showPo po-      showPr (_,pr,_) = pr ++ " " -      showPo po = concat $ intersperse "," $ map show po-      showEx ex = if (null ex) then "" else (showSem ex)-      -}-      -- recursive step-  in if null blacklist-     then oldAut { states = (reverse oldSt) ++ (sts:next) }-     else prune' next newAut -\end{code}--% ====================================================================-\section{Zero-literal semantics}-\label{sec:multiuse}-\label{semantic_weights}-\label{sec:nullsem}-\label{sec:co-anchors}-% ====================================================================--Lexical items with a \jargon{null semantics} typically correspond to-functions words: complementisers \natlang{(John likes \textbf{to}-read.)}, subcategorised prepositions \natlang{(Mary accuses John-\textbf{of} cheating.)}.  Such items need not be lexical items at all.-We can exploit TAG's support for trees with multiple anchors, by-treating them as co-anchors to some primary lexical item. The English-infinitival \natlang{to}, for example, can appear in the tree-\tautree{to~take} as \koweytree{s(comp(to),v(take),np$\downarrow$)}. --On the other hand, pronouns have a \jargon{zero-literal} semantics, one-which is not null, but which consists only of a variable index.  For-example, the pronoun \natlang{she} in (\ref{ex:pronoun_pol_she}) has-semantics \semexpr{s} and in (\ref{ex:pronoun_pol_control}),-\natlang{he} has the semantics \semexpr{j}.  --{\footnotesize-\eenumsentence{\label{ex:pronoun_pol} -\item \label{ex:pronoun_pol_sue} -\semexpr{joe(j), sue(s), book(b), lend(l,j,b,s), boring(b) }  -\\ \natlang{Joe lends Sue a boring book.}--% Note for visually impaired readers: ignore anything with \color{white}. -% It is used as a form of indentation to help sighted users. -\item \label{ex:pronoun_pol_she} -\semexpr{joe(j), {\color{white}sue(s),} book(b), lend(l,j,b,s), boring(b) }  -\\ \natlang{Joe lends her a boring book.}-}-\eenumsentence{\label{ex:pronoun_pol_control} -\item[{\color{white}a.}] \label{ex:pronoun_pol_control_inf}-\semexpr{joe(j), sue(s), leave(l,j), promise(p,j,s,l)}-\\ \natlang{Joe promises Sue to leave.}-\\ or \natlang{Joe promises Sue that he would leave.} -}}--In figure \ref{fig:polarity_automaton_zerolit_bad}, we compare the-construction of polarity automata for (\ref{ex:pronoun_pol_sue}, left)-and (\ref{ex:pronoun_pol_she}, right).  Building an automaton for-(\ref{ex:pronoun_pol_she}) fails because \tautree{sue} is not available-to cancel the negative polarities for \tautree{lends}; instead, a-pronoun must be used to take its place.  The problem is that the-selection of a lexical items is only triggered when the construction-algorithm visits one of its semantic literals.  Since pronoun semantics-have zero literals, they are \emph{never} selected.  Making pronouns-visible to the construction algorithm would require us to count the-indices from the input semantics.  Each index refers to an entity.  This-entity must be ``consumed'' by a syntactic functor (e.g. a verb) and-``provided'' by a syntactic argument (e.g. a noun).--%\footnote{This also holds true for sentences like \natlang{Joe sings-%badly and Sue sings well}, \semexpr{sing(s1,j) good(s1), sing(s2,m),-%bad(s2)} because each usage of \natlang{sings} actually corresponds to a-%different lexical item, \tautree{sings1} with the semantics-%\semexpr{sings(s1,j)} and \tautree{sings2} with \semexpr{sings(s2,m)}.}.  --\begin{figure}[htpb]-\begin{center}-\includegraphics[scale=0.25]{images/zeroaut-noun.pdf}-\includegraphics[scale=0.25]{images/zeroaut-sans.pdf}-\end{center}-\vspace{-0.4cm}-\caption{Difficulty with zero-literal semantics.}-\label{fig:polarity_automaton_zerolit_bad}-\end{figure}--We make this explicit by annotating the semantics of the lexical input-(that is the set of lexical items selected on the basis of the input-semantics) with a form of polarities.  Roughly, nouns provide-indices\footnote{except for predicative nouns, which like verbs, are-semantic functors} ($+$), modifiers leave them unaffected, and verbs-consume them ($-$).  Predicting pronouns is then a matter of counting-the indices.  If the positive and negative indices cancel each other-out, no pronouns are required.  If there are more negative indices than-positive ones, then as many pronouns are required as there are negative-excess indices.  In the table below, we show how the example semantics-above may be annotated and how many negative excess indices result:--\begin{center}-{\footnotesize-\begin{tabular}{|l|r|r|r|}-\hline-\multicolumn{1}{|c|}{\bf semantics} & -{\bf \tt b} &-{\bf \tt j} & -{\bf \tt s} \\ -\hline-\semexpr{joe(+j)  sue(+s)  book(+b)  lend(l,-j,-b,-s)  boring(b)} & -\semexpr{0} &-\semexpr{0} &-\semexpr{0} \\-\hline-\semexpr{joe(+j)  {\color{white}sue(+s)} book(+b)  lend(l,-j,-b,-s)  boring(b)} & -\semexpr{0} &-\semexpr{0} &-\semexpr{1} \\-\hline-\semexpr{joe(+j) sue(+s) leave(l,-j,-s) promise(p,{\color{white}-}j,-s,l)} &-\semexpr{0} &-\semexpr{0} & -\semexpr{0} \\ -\hline-\semexpr{joe(+j) sue(+s) leave(l,-j,-s) promise(p,-j,-s,l)} &-\semexpr{0} &-\semexpr{1} & -\semexpr{0} \\ -\hline-\end{tabular}-}-\end{center}--Counting surplus indices allows us to establish the number of pronouns-used and thus gives us the information needed to build polarity-automata.  We implement this by introducing a virtual literal for-negative excess index, and having that literal be realised by pronouns.-Building the polarity automaton as normal yields lexical combinations-with the required number of pronouns, as in figure-\ref{fig:polarity_automaton_zerolit}.   --\begin{figure}[htpb]-\begin{center}-\includegraphics[scale=0.25]{images/zeroaut-pron.pdf}-\end{center}-\vspace{-0.4cm}-\caption{Constructing a polarity automaton with zero-literal semantics.}-\label{fig:polarity_automaton_zerolit}-\end{figure}--\label{different_sem_annotations}-The sitation is more complicated where the lexical input-contains lexical items with different annotations for the same-semantics.  For instance, the control verb \natlang{promise} has two-forms: one which solicits an infinitive as in \natlang{promise to-leave}, and one which solicits a declarative clause as in-\natlang{promise that he would leave}.  This means two different counts-of subject index \semexpr{j} in (\ref{ex:pronoun_pol_control}) : zero-for the form that subcategorises for the infinitive, or one for the-declarative.  But to build a single automaton, these counts must be-reconciled, i.e., how many virtual literals do we introduce for-\semexpr{j}, zero or one?  The answer is to introduce enough virtual-literals to satisfy the largest demand, and then use the multi-literal-extension to support alternate forms with a smaller demand.  To handle-example (\ref{ex:pronoun_pol_control}), we introduce one virtual literal-for \semexpr{j} so that the declarative form can be produced, and treat-the soliciting \natlang{promise} as though its semantics includes that-literal along with its regular semantics (figure-\ref{fig:polarity_automaton_zerolit_promise}).  In other words, the-infinitive-soliciting form is treated as if it already fulfils the role-of a pronoun, and does not need one in its lexical combination.--\begin{figure}[htpb]-\begin{center}-\includegraphics[scale=0.25]{images/zeroaut-promise.pdf}-\end{center}-\vspace{-0.4cm}-\caption{Constructing a polarity automaton with zero-literal semantics.}-\label{fig:polarity_automaton_zerolit_promise}-\end{figure}--We insert pronouns into the input semantics using the following process:-\begin{enumerate}-\item For each literal in the input semantics, establish the-      smallest charge for each of its semantic indices.-\item Cancel out the polarities for every index in the input-      semantics.-\item Compensate for any uncancelled negative polarities by an-      adding an additional literal to the input semantics -- a pronoun ---      for every negative charge.-\item Finally, deal with the problem of lexical items who require fewer-      pronouns than predicted by inserting the excess pronouns in their extra-      literal semantics (see page \pageref{different_sem_annotations})-\end{enumerate}--\begin{code}-type PredLite = (String,[GeniVal]) -- handle is head of arg list -type SemWeightMap = Map.Map PredLite SemPols---- | Returns a modified input semantics and lexical selection in which pronouns---   are properly accounted for.-fixPronouns :: (Sem,[TagElem]) -> (Sem,[TagElem])-fixPronouns (tsem,cands) = -  let -- part 1 (for each literal get smallest charge for each idx)-      getpols :: TagElem -> [ (PredLite,SemPols) ]-      getpols x = zip [ (show p, h:as) | (h,p,as) <- tsemantics x ] (tsempols x)-      sempols :: [ (PredLite,SemPols) ]-      sempols = concatMap getpols cands-      usagemap :: SemWeightMap -      usagemap = Map.fromListWith (zipWith min) sempols-      -- part 2 (cancel sem polarities)-      chargemap :: Map.Map GeniVal Int -- index to charge -      chargemap =  Map.fromListWith (+) $ concatMap clump $ Map.toList usagemap-        where clump ((_,is),ps) = zip is ps-      -- part 3 (adding extra semantics)-      indices = concatMap fn (Map.toList chargemap) -        where fn (i,c) = replicate (negate c) i-      -- the extra columns -      extraSem = map indexPred indices-      tsem2    = sortSem (tsem ++ extraSem)-      -- zero-literal semantic items to realise the extra columns -      zlit = filter (null.tsemantics) cands-      cands2 = (cands \\ zlit) ++ concatMap fn indices-        where fn i = map (tweak i) zlit-              tweak i x = assignIndex i $ x { tsemantics = [indexPred i] }-      -- part 4 (insert excess pronouns in tree sem)-      comparefn :: GeniVal -> Int -> Int -> [GeniVal]-      comparefn i ct cm = if cm < ct then extra else []-        where maxNeeded = Map.findWithDefault 0 i chargemap -- cap the number added-              extra = replicate (min (negate maxNeeded) (ct - cm)) i-      comparePron :: (PredLite,SemPols) -> [GeniVal]-      comparePron (lit,c1) = concat $ zipWith3 comparefn idxs c1 c2-        where idxs = snd lit-              c2   = Map.findWithDefault [] lit usagemap-      addextra :: TagElem -> TagElem-      addextra c = c { tsemantics = sortSem (sem ++ extra) }-        where sem   = tsemantics c-              extra = map indexPred $ concatMap comparePron (getpols c)-      cands3 = map addextra cands2-  in (tsem2, cands3)---- | Builds a fake semantic predicate that the index counting mechanism uses to---   represent extra columns.-indexPred :: GeniVal -> Pred-indexPred x = (x, GAnon, [])---- Returns True if the given literal was introduced by the index counting mechanism-isExtraCol :: Pred -> Bool-isExtraCol (_,GAnon,[]) = True-isExtraCol _            = False-\end{code}--\paragraph{assignIndex} is a useful way to restrict the behaviour of-null semantic items like pronouns using the information generated by-the index counting mechanism.  The problem with null semantic items -is that their indices are not set, which means that they could-potentially combine with any other tree.  To make things more -efficient, we can set the index of these items and thus reduce the-number of spurious combinations.  --Notes-\begin{itemize}-%\item These combinations could produce false results if the-%input has to use multiple pronouns.  For example, if you wanted to say-%something like \natlang{John promises Mary to convince Paul to give her-%  his book}, these combinations could instead produce \natlang{give him-%    \textbf{her} book}.-\item This function works by FS unification on the root node of the-  tree with the \fs{\it idx:i\\}.  If unification is not possible, -  we simply return the tree as is.-\item This function renames the tree by appending the index to its name-\end{itemize}--\begin{code}-assignIndex :: GeniVal -> TagElem -> TagElem -assignIndex i te =-  let idxfs = [ AvPair __idx__ i ]-      oldt  = ttree te-      oldr  = root oldt-      tfup  = gup oldr-      ---  in case unifyFeat tfup idxfs of-     Nothing          -> te-     Just (gup2, sub) -> replace sub $ te { ttree = newt }-       where newt = rootUpd oldt $ oldr { gup = gup2 }-\end{code}---% ====================================================================-\section{Further optimisations}-% ====================================================================--\subsection{Lexical filtering} \label{fn:detectIdxConstraints}--Lexical filtering allows the user to constrain the lexical selection-to only those items that contain a certain property, for example, the-realising an item as a cleft.--The idea is that the user provides an input like-\verb$idxconstraints:[cleft:j]$,-which means that the lexical selection must include exactly one tree-with the property cleft:j in its interface.  This mechanism works as-pre-processing step after lexical selection and before polarity-automaton construction, in conjuction with the ExtraPolarities-mechanism.  What we do is--\begin{enumerate}-\item Preprocess the lexically selected trees; any tree which has a-      a desired property (e.g. cleft:j) in its interface is assigned-      a positive polarity for that property (+cleft:j)-\item Add all the index constraints as negative extra polarities (-cleft:j)-\end{enumerate}--Note: we assume the index constraints and interface are sorted; also, we-prefix the index constraint polarities with a ``.'' because they are likely to-be very powerful filters and we would like them to be used first.--\begin{code}-detectIdxConstraints :: Flist -> Flist -> PolMap -detectIdxConstraints cs interface =-  let matches  = intersect cs interface-      matchStr = map idxConstraintKey matches-  in Map.fromList $ zip matchStr ((repeat.ival) 1)--declareIdxConstraints :: Flist -> PolMap-declareIdxConstraints = Map.fromList . (map declare) where-   declare c = (idxConstraintKey c, minusone)-   minusone = ival (-1)--idxConstraintKey :: AvPair -> PolarityKey-idxConstraintKey = PolarityKey . ('.' :) . showAv-\end{code}--\subsection{Automatic detection}--Automatic detection is not an optimisation in itself, but a means to-make grammar development with polarities more convenient.--\paragraph{Which attributes should we use?} Our detection process looks for-attributes which are defined on \emph{all} subst and root nodes of the-lexically selected items.  Note that this should typically give you the-\verb!cat! and \verb!idx! polarities.--\begin{code}-detectPolFeatures :: [TagElem] -> [String]-detectPolFeatures tes =-  let -- only initial trees need be counted; in aux trees, the-      -- root node is implicitly canceled by the foot node-      rfeats, sfeats :: [Flist]-      rfeats = map (gdown.root.ttree) $ filter (\t -> ttype t == Initial) tes-      sfeats = [ concat s | s <- map substTops tes, (not.null) s ]-      ---      attrs :: Flist -> [String]-      attrs avs = [ a | AvPair a v <- avs, isConst v ]-      theAttributes = map attrs $ rfeats ++ sfeats-  in if null tes then [] else foldr1 intersect theAttributes---- FIXME: temporary HACKY code - delete me as soon as possible (written--- 2006-03-30------ only initial trees need be counted; in aux trees, the--- root node is implicitly canceled by the foot node-detectSansIdx :: [TagElem] -> [TagElem]-detectSansIdx =-  let rfeats t = (gdown.root.ttree) t-      feats  t | ttype t == Initial = concat $ rfeats t : substTops t-      feats  t = concat $ substTops t-      attrs avs = [ a | AvPair a v <- avs, isConst v ]-      hasIdx t = __idx__ `elem` (attrs.feats $ t) || (ttype t /= Initial && (null $ substTops t))-  in filter (not.hasIdx)-\end{code}--\paragraph{The polarity values}-First the simplified explanation: we assign every tree with a $-1$ charge for-every category for every substitution node it has.  Additionally, we assign-every initial tree with a $+1$ charge for the category of its root node.  So-for example, the tree s(n$\downarrow$, cl$\downarrow$, v(aime), n$\downarrow$)-should have the following polarities: s +1, cl -1, n -2. These charges are-added to any that previously been defined in the grammar.--Now what really happens: we treat automaton polarities as intervals, not -as single integers!  For the most part, nothing changes from the simplified-explanation.  Where we added a $-1$ charge before, we now add a $(-1,-1)$-charge.  Similarly, we where added a $+1$ charge, we now add $(1,1)$.  So-what's the point of all this?  It helps us deal with atomic disjunction.--\subparagraph{Atomic disjunction} Say we encounter a substitution node -whose category is either cl or n.  What we do is add the polarities-$cl (-1,0),  n (-1,0)$ which means that there are anywhere from -1 to -0 cl, and for n.  -FIXME: What kind of sucks about all this though is that this slightly worsens-the filter because it allows for both cl and n to be $-1$ (or $0$) at the same-time.  It would be nice to have some kind of mutual exclusion working.--\begin{code}-detectPols :: Set.Set PolarityAttr -> [TagElem] -> [TagElem]-detectPols attrs = map (detectPolsH attrs)--detectPolsH :: Set.Set PolarityAttr -> TagElem -> TagElem-detectPolsH polarityAttrs te =-  let detectOrBust x1 x2 x3 x4 =-        case detectPolarity x1 x2 x3 x4 of-        PD_UserError e -> error $ e ++ " in " ++ tgIdName te -- ideally we'd propagate this-        PD_Nothing     -> []-        PD_Just p      -> p-      ---      rup   = gup . root .ttree $ te-      rdown = gdown . root . ttree $ te-      ---      catAttr = SimplePolarityAttr "cat"-      rstuffLite  = concatMap (\v -> detectOrBust 1 v rup rdown)-                  $ Set.toList $ Set.delete catAttr polarityAttrs-      rstuff :: [(PolarityKey,Interval)]-      rstuff   = if Set.member catAttr polarityAttrs-                    then -- cat is considered global to the whole tree to be-                         -- robust, we grab it from the top feature-                         detectOrBust 1 catAttr rup rup ++ rstuffLite-                    else rstuffLite-      substuff :: [(PolarityKey,Interval)]-      substuff = let tops = substTops te-                     detect :: PolarityAttr -> [(PolarityKey,Interval)]-                     detect v = concat $ zipWith (detectOrBust (-1) v) tops tops-                 in concatMap detect $ Set.toList polarityAttrs-      -- substs and roots-      pols  = case ttype te of-                Initial -> substuff ++ rstuff-                _       -> substuff-      ---      oldfm = tpolarities te-  in te { tpolarities = foldr addPol oldfm pols }--__cat__, __idx__  :: String-__cat__  = "cat"-__idx__  = "idx"---data PolarityDetectionResult = PD_UserError String-                             | PD_Nothing-                             | PD_Just [ (PolarityKey, Interval) ]---- | Careful, this completely ignores any user errors-pdJusts :: [PolarityDetectionResult] -> [(PolarityKey,Interval)]-pdJusts = concatMap helper- where helper (PD_Just x) = x-       helper _           = []--detectPolarity :: Int          -- ^ polarity to assign-               -> PolarityAttr -- ^ attribute to look for-               -> Flist        -- ^ feature structure to filter on-               -> Flist        -- ^ feature structure to get value from-               -> PolarityDetectionResult-detectPolarity i (RestrictedPolarityAttr cat att) filterFl fl =-  case [ v | AvPair a v <- filterFl, a == __cat__ ] of-    []  -> PD_UserError $ "[polarities] No category " ++ cat ++ " in:" ++ showFlist filterFl-    [v] -> if isJust (unify [GConst [cat]] [v])-              then detectPolarityForAttr i att fl-              else PD_Nothing-    _   -> PD_UserError $ "[polarities] More than one category " ++ " in:" ++ showFlist filterFl-detectPolarity i (SimplePolarityAttr att) _ fl = detectPolarityForAttr i att fl--detectPolarityForAttr :: Int -- ^ polarity to assign-                      -> String-                      -> Flist-                      -> PolarityDetectionResult-detectPolarityForAttr i att fl =-  case [ v | AvPair a v <- fl, a == att ] of-    []  -> PD_UserError $ "[polarities] No value for attribute: " ++ att ++ " in:" ++ showFlist fl-    [v] -> if isConst v-              then PD_Just $ case prefixWith att (fromGConst v) of-                             [x] -> [ (PolarityKey x, ival i) ]                -- singleton-                             xs  -> map (\x -> (PolarityKey x, toZero i)) xs   -- interval if ambiguous-              else PD_UserError $ "[polarities] Non-constant value for attribute: " ++ att ++ " in:" ++ showFlist fl-    _   -> PD_UserError $ "[polarities] More than one value for attribute: " ++ att ++ " in:" ++ showFlist fl--toZero :: Int -> Interval-toZero x | x < 0     = (x, 0)-         | otherwise = (0, x)--prefixWith :: String -> [String] -> [String]-prefixWith att = map (\x -> att ++ ('_' : x))--substNodes :: TagElem -> [GNode]-substNodes t = [ gn | gn <- (flatten.ttree) t, gtype gn == Subs ]--substTops :: TagElem -> [Flist]-substTops = map gup . substNodes-\end{code}--\subsection{Chart sharing}--Chart sharing is based on the idea that instead of performing a -seperate generation task for each automaton path, we should do-single generation task, but annotate each tree with set of the-automata paths it appears on.  We then allow trees on the-same paths to be compared only if they are on the same path.-Note: chart sharing involves some mucking around with the generation-engine (see page \pageref{fn:Builder:preInit})--\begin{code}--- | Given a list of paths (i.e. a list of list of trees)---   return a list of trees such that each tree is annotated with the paths it---   belongs to.-detectPolPaths :: [[TagElem]] -> [(TagElem,BitVector)]-detectPolPaths paths = -  let pathFM     = detectPolPaths' Map.empty 0 paths-      lookupTr k = Map.findWithDefault 0 k pathFM-  in map (\k -> (k, lookupTr k)) $ Map.keys pathFM--type PolPathMap = Map.Map TagElem BitVector-detectPolPaths' :: PolPathMap -> Int -> [[TagElem]] -> PolPathMap  --detectPolPaths' accFM _ [] = accFM-detectPolPaths' accFM counter (path:ps) = -  let currentBits = shiftL 1 counter -- shift counter times the 1 bit-      fn f []     = f-      fn f (t:ts) = fn (Map.insertWith (.|.) t currentBits f) ts -      newFM       = fn accFM path-  in detectPolPaths' newFM (counter+1) ps---- | Render the list of polarity automaton paths as a string-showPolPaths :: BitVector -> String-showPolPaths paths =-  let pathlist = showPolPaths' paths 1-  in concat $ intersperse ", " $ map show pathlist--showPolPaths' :: BitVector -> Int -> [Int] -showPolPaths' 0 _ = []-showPolPaths' bv counter = -  if b then (counter:next) else next-  where b = testBit bv 0-        next = showPolPaths' (shiftR bv 1) (counter + 1)-\end{code}--\subsection{Semantic sorting}--To minimise the number of states in the polarity automaton, we could-also sort the literals in the target semantics by the number of-corresponding lexically selected items.  The idea is to delay branching-as much as possible so as to mimimise the number of states in the-automaton.--Let's take a hypothetical example with two semantic literals:-bar (having two trees with polarties 0 and +1).-foo (having one tree with polarity -1) and-If we arbitrarily explored bar before foo (no semantic sorting), the-resulting automaton could look like this:--\begin{verbatim}-     bar     foo-(0)--+---(0)------(-1)-     |               -     +---(1)------(0)-\end{verbatim}--With semantic sorting, we would explore foo before bar because foo has-fewer items and is less likely to branch.  The resulting automaton-would have fewer states.--\begin{verbatim}-     foo      bar-(0)-----(-1)--+---(-1)-              |        -              +---(0)-\end{verbatim}--The hope is that this would make the polarity automata a bit-faster to build, especially considering that we are working over-multiple polarity keys.  --Note: we have to take care to count each literal for each lexical-entry's semantics or else the multi-literal semantic code will choke.--\begin{code}-sortSemByFreq :: Sem -> [TagElem] -> Sem-sortSemByFreq tsem cands = -  let counts = map lenfn tsem -      lenfn l = length $ filter fn cands -                where fn x = l `elem` (tsemantics x)-      -- note: we introduce an extra hack to push-      -- index-counted extra columns to the end; just for UI reasons-      sortfn a b -        | isX a && isX b = compare (snd a) (snd b)-        | isX a          = GT-        | isX b          = LT-        | otherwise      = compare (snd a) (snd b)-        where isX = isExtraCol.fst -      sorted = sortBy sortfn $ zip tsem counts -  in (fst.unzip) sorted -\end{code}--% -----------------------------------------------------------------------\section{Types}-% ------------------------------------------------------------------------\begin{code}-type SemMap = Map.Map Pred [TagElem]-type PolMap = Map.Map PolarityKey Interval---- | Adds a new polarity item to a 'PolMap'.  If there already is a polarity---  for that item, it is summed with the new polarity.-addPol :: (PolarityKey,Interval) -> PolMap -> PolMap-addPol (p,c) m = Map.insertWith (!+!) p c m---- | Ensures that all states and transitions in the polarity automaton---   are unique.  This is a slight optimisation so that we don't have to---   repeatedly check the automaton for state uniqueness during its---   construction, but it is essential that this check be done after---   construction-nubAut :: (Ord ab, Ord st) => NFA st ab -> NFA st ab -nubAut aut = -  aut {-      transitions = Map.map (\e -> Map.map nub e) (transitions aut)-  }-\end{code}--\subsection{Polarity NFA}--We can define the polarity automaton as a NFA, or a five-tuple -$(Q, \Sigma, \delta, q_0, q_n)$ such that --\begin{enumerate}-\item $Q$ is a set of states, each state being a tuple $(i,e,p)$ where $i$-is an integer (representing a single literal in the target semantics), -$e$ is a list of extra literals-which are known by the state, and $p$ is a polarity.-\item $\Sigma$ is the union of the sets of candidate trees for all-propositions-\item $q_0$ is the start state $(0,[0,0])$ which does not correspond to any-propositions and is used strictly as a starting point.-\item $q_n$ is the final state $(n,[x,y])$ which corresponds to the last-proposition, with polarity $x \leq 0 \leq y$.-\item $\delta$ is the transition function between states, which we-define below.-\end{enumerate}--Note: -\begin{itemize}-\item For convenience during automaton intersection, we actually define-      the states as being $(i, [(p_x,p_y)])$ where $[(p_x,p_y)]$ is a list of-      polarity intervals.  -\item We use integer $i$ for each state instead of literals directly,-      because it is possible for the target semantics to contain the -      same literal twice (at least, with the index counting mechanism-      in place)-\end{itemize}--\begin{code}-data PolState = PolSt Int [Pred] [(Int,Int)]     -                -- ^ position in the input semantics, extra semantics, -                --   polarity interval-     deriving (Eq)-type PolTrans = TagElem-type PolAut   = NFA PolState PolTrans-type PolTransFn = Map.Map PolState (Map.Map PolState [Maybe PolTrans])--instance Show PolState-  where show (PolSt pr ex po) = show pr ++ " " ++ showSem ex ++ show po--- showPred pr ++ " " ++ showSem ex ++ show po--instance Ord PolState where-  compare (PolSt pr1 ex1 po1) (PolSt pr2 ex2 po2) = -    let prC   = compare pr1 pr2-        expoC = compare (ex1,po1) (ex2,po2)-    in if (prC == EQ) then expoC else prC-\end{code}--We include also some fake states which are useful for general-housekeeping during the main algortihms.--\begin{code}-fakestate :: Int -> [Interval] -> PolState-fakestate s pol = PolSt s [] pol --PolSt (0, s, [""]) [] pol---- | an initial state for polarity automata-polstart :: [Interval] -> PolState-polstart pol = fakestate 0 pol -- fakestate "START" pol-\end{code}--% -----------------------------------------------------------------------\section{Display code}-\label{sec:display_pol}-% ------------------------------------------------------------------------\begin{code}--- | 'showLite' is like Show but it's only used for debugging---   TODO: is this true?-class ShowLite a where-  showLite :: a -> String--instance (ShowLite a) => ShowLite [a] where-  showLite x = "[" ++ (concat $ intersperse ", " $ map showLite x) ++ "]"-instance (ShowLite a, ShowLite b) => ShowLite (a,b) where-  showLite (x,y) = "(" ++ (showLite x) ++ "," ++ (showLite y) ++ ")"--instance ShowLite Int where showLite = show -instance ShowLite Char where showLite = show -\end{code}--%\begin{code}-%instance (Show st, ShowLite ab) => ShowLite (NFA st ab) where-%  showLite aut = -%    concatMap showTrans $ toList (transitions aut)-%    where showTrans ((st1, x), st2) = show st1 ++ showArrow x -%                                 ++ show st2 ++ "\n"-%          showArrow x = " --" ++ showLite x ++ "--> " -%        -- showSt (PolSt pr po) = show po-%\end{code}--\begin{code}-instance ShowLite TagElem where-  showLite = idname --{---- | Display a SemMap in human readable text.-showLiteSm :: SemMap -> String-showLiteSm sm = -  concatMap showPair $ toList sm -  where showPair  (pr, cs) = showPred pr ++ "\t: " ++ showPair' cs ++ "\n"-        showPair' [] = ""-        showPair' (te:cs) = tlIdname te ++ "[" ++ showLitePm (tpolarities te) ++ "]"-                                        ++ " " ++ showPair' cs --}---- | Display a PolMap in human-friendly text.---   The advantage is that it displays fewer quotation marks.-showLitePm :: PolMap -> String-showLitePm pm = -  let showPair (f, pol) = showInterval pol ++ fromPolarityKey f-  in concat $ intersperse " " $ map showPair $ Map.toList pm-\end{code}
+ src/NLP/GenI/Polarity/Internal.hs view
@@ -0,0 +1,190 @@+-- GenI surface realiser+-- Copyright (C) 2009 Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.++{-# LANGUAGE OverloadedStrings #-}+module NLP.GenI.Polarity.Internal where++import Control.Applicative+import Data.List+import Data.Maybe (isJust)+import Data.Text (Text)+import Data.Tree (flatten)+import qualified Data.Map as Map+import qualified Data.Set as Set+import qualified Data.Text as T++import Data.FullList hiding ( (++) )+import NLP.GenI.Automaton+import NLP.GenI.FeatureStructure+import NLP.GenI.General+import NLP.GenI.GeniVal+import NLP.GenI.Polarity.Types+import NLP.GenI.Pretty+import NLP.GenI.Semantics (Literal)+import NLP.GenI.Tag ( TagElem(..), TagItem(..) )+import NLP.GenI.TreeSchema+    ( Ptype(Initial)+    , GNode, root, gup, gdown, gtype, GType(Subs),+    )++data PolarityDetectionResult = PD_UserError String+                             | PD_Nothing+                             | PD_Just [ (PolarityKey, Interval) ]+                             | PD_Unconstrained (Text, Interval)++-- ----------------------------------------------------------------------+-- polarity detection+-- ----------------------------------------------------------------------++-- | Given a description of what the root feature should unify with+--   return a -1 polarity for all relevant polarity keys. This allows+--   us to compensate for the root node of any derived tree. +detectRootCompensation :: Set.Set PolarityAttr -> FeatStruct GeniVal -> PolMap+detectRootCompensation polarityAttrs rootFeat =+  Map.fromListWith (!+!) . pdResults+    $ map (\v -> detectPolarity (-1) (SimplePolarityAttr (pAttr v)) emptyFeatStruct rootFeat)+    $ Set.toList polarityAttrs+  where+   pAttr p@(SimplePolarityAttr _)       = spkAtt p+   pAttr p@(RestrictedPolarityAttr _ _) = rpkAtt p++detectPolsH :: Set.Set PolarityAttr -> TagElem -> [(PolarityKey,Interval)]+detectPolsH polarityAttrs te =+   case ttype te of+    Initial -> substuff ++ rstuff+    _       -> substuff+  where+   pdError e = e ++ " in " ++ T.unpack (tgIdName te) -- ideally we'd propagate this+   detectOrBust x1 x2 x3 x4 = pdToList pdError (detectPolarity x1 x2 x3 x4)+   --+   rup   = mkFeatStruct . gup . root .ttree $ te+   rdown = mkFeatStruct . gdown . root . ttree $ te+   --+   catAttr = SimplePolarityAttr "cat"+   rstuffLite  = concatMap (\v -> detectOrBust 1 v rup rdown)+               $ Set.toList $ Set.delete catAttr polarityAttrs+   rstuff   = if Set.member catAttr polarityAttrs+                 then -- cat is considered global to the whole tree,+                      -- but to be robust, we grab it from the top feature+                      detectOrBust 1 catAttr rup rup ++ rstuffLite+                 else rstuffLite+   substuff = let tops = map mkFeatStruct (substTops te)+                  detect :: PolarityAttr -> [(PolarityKey,Interval)]+                  detect v = concat $ zipWith (detectOrBust (-1) v) tops tops+              in concatMap detect $ Set.toList polarityAttrs++detectPolarity :: Int          -- ^ polarity to assign+               -> PolarityAttr -- ^ attribute to look for+               -> FeatStruct GeniVal -- ^ feature structure to filter on ('RestrictedPolarityAttr' only)+               -> FeatStruct GeniVal -- ^ feature structure to get value from+               -> PolarityDetectionResult+detectPolarity i (RestrictedPolarityAttr cat att) filterFl fl =+  case Map.lookup __cat__ filterFl of+    Nothing -> PD_UserError . T.unpack $ "[polarities] No category "+                  `T.append` cat+                  `T.append` " in:"+                  `T.append` pretty filterFl+    Just v -> if isJust (unify [mkGConstNone cat] [v])+              then detectPolarity i (SimplePolarityAttr att) emptyFeatStruct fl+              else PD_Nothing+detectPolarity i (SimplePolarityAttr att) _ fl =+  case Map.lookup att fl of+    Nothing -> PD_Unconstrained (withZero att)+    Just v  -> case fromFL <$> gConstraints v of+             Just [x] -> PD_Just [ (PolarityKeyAv att x, ival i) ]       -- singleton+             Just xs  -> PD_Just $ map (withZero . PolarityKeyAv att) xs   -- interval if ambiguous+             Nothing  -> PD_Unconstrained (withZero att)+ where+   withZero x = (x, toZero i)++toZero :: Int -> Interval+toZero x | x < 0     = (x, 0)+         | otherwise = (0, x)++substNodes :: TagElem -> [GNode GeniVal]+substNodes t = [ gn | gn <- (flatten.ttree) t, gtype gn == Subs ]++substTops :: TagElem -> [Flist GeniVal]+substTops = map gup . substNodes++type SemMap = Map.Map (Literal GeniVal) [TagElem]+type PolMap = Map.Map PolarityKey Interval++-- ----------------------------------------------------------------------+-- after polarity detection+-- ----------------------------------------------------------------------++polarityKeys :: [TagElem] -> PolMap -> [PolarityKey]+polarityKeys cands extraPol =+  sortBy (flip compare) $ nub $ ksCands ++ ksExtra+ where+  ksCands = concatMap (Map.keys . tpolarities) cands+  ksExtra = Map.keys extraPol++-- | Convert any unconstrained polarities in a 'PolMap' to constrained+--   ones, assuming a global list of known constrained keys.+convertUnconstrainedPolarities :: [PolarityKey] -> PolMap -> PolMap+convertUnconstrainedPolarities ks pmap =+   addPols expansions con+  where+   (con, uncon) = Map.partitionWithKey constrained pmap+   constrained (PolarityKeyVar _) _ = False+   constrained _   _ = True+   --+   expansions =  [ (k,v) | (PolarityKeyVar  a, v)   <- Map.toList uncon+                         , k@(PolarityKeyAv a2 _) <- ks+                         , a == a2+                 ]++-- ----------------------------------------------------------------------+-- helpers+-- ----------------------------------------------------------------------++-- duplicates are a matter of course+addPols :: [(PolarityKey,Interval)] -> PolMap -> PolMap +addPols pols m = foldr f m pols+ where+  f (p,c) = Map.insertWith (!+!) p c++-- | Ensures that all states and transitions in the polarity automaton+--   are unique.  This is a slight optimisation so that we don't have to+--   repeatedly check the automaton for state uniqueness during its+--   construction, but it is essential that this check be done after+--   construction+nubAut :: (Ord ab, Ord st) => NFA st ab -> NFA st ab+nubAut aut =+  aut {+      transitions = Map.map (\e -> Map.map nub e) (transitions aut)+  }++__cat__, __idx__  :: Text+__cat__  = "cat"+__idx__  = "idx"+++-- | Note that this will crash if any of the entries are errors+pdResults :: [PolarityDetectionResult] -> [(PolarityKey, Interval)]+pdResults = concatMap (pdToList id)++-- | Note that this will crash if any of the entries are errors+pdToList :: (String -> String) -- ^ on error message+         -> PolarityDetectionResult+         -> [(PolarityKey,Interval)]+pdToList _ (PD_Just x) = x+pdToList f (PD_UserError e) = error (f e)+pdToList _ (PD_Unconstrained (k,i)) = [ (PolarityKeyVar k, i) ]+pdToList _ PD_Nothing = []
+ src/NLP/GenI/Polarity/Types.hs view
@@ -0,0 +1,84 @@+-- GenI surface realiser+-- Copyright (C) 2009 Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.++{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE OverloadedStrings #-}++module NLP.GenI.Polarity.Types where++import qualified Data.Set as Set+import Data.Generics ( Data )+import Data.Typeable ( Typeable )+import Data.Text ( Text )+import qualified Data.Text as T++import Control.DeepSeq++import NLP.GenI.Pretty++data PolarityKey = PolarityKeyAv   Text Text+                 | PolarityKeyStr  Text+                 | PolarityKeyVar  Text -- ^ attribute+ deriving (Eq, Ord, Data, Typeable)++instance Pretty PolarityKey where+  pretty (PolarityKeyAv a v) = a <> ":" <> v+  pretty (PolarityKeyStr s)  = s+  pretty (PolarityKeyVar a)  = a <> ":_"++type SemPols  = [Int]++-- | 'PolarityAttr' is something you want to perform detect polarities on.+data PolarityAttr = SimplePolarityAttr { spkAtt :: Text }+ -- | 'RestrictedPolarityKey' @c att@ is a polarity key in which we only pay+ --   attention to nodes that have the category @c@.  This makes it possible+ --   to have polarities for a just a small subset of nodes+ | RestrictedPolarityAttr { _rpkCat :: Text, rpkAtt :: Text }+ deriving (Eq, Ord, Typeable)++readPolarityAttrs :: String -> Set.Set PolarityAttr+readPolarityAttrs = Set.fromList . map helper . words+ where+  helper s = case break (== '.') s of+             (a,"") -> SimplePolarityAttr (T.pack a)+             (c,a)  -> RestrictedPolarityAttr (T.pack c) (T.pack (drop 1 a))++showPolarityAttrs :: Set.Set PolarityAttr -> String+showPolarityAttrs = unwords . map show . Set.toList++instance Show PolarityAttr where+ show (SimplePolarityAttr a) = T.unpack a+ show (RestrictedPolarityAttr c a) = T.unpack c ++ "." ++ T.unpack a++{-!+deriving instance NFData PolarityKey+deriving instance NFData PolarityAttr+!-}+-- GENERATED START++ +instance NFData PolarityKey where+        rnf (PolarityKeyAv x1 x2) = rnf x1 `seq` rnf x2 `seq` ()+        rnf (PolarityKeyStr x1 )  = rnf x1 `seq` ()+        rnf (PolarityKeyVar x1 )  = rnf x1 `seq` ()++ +instance NFData PolarityAttr where+        rnf (SimplePolarityAttr x1) = rnf x1 `seq` ()+        rnf (RestrictedPolarityAttr x1 x2) = rnf x1 `seq` rnf x2 `seq` ()+-- GENERATED STOP
− src/NLP/GenI/PolarityTypes.hs
@@ -1,44 +0,0 @@--- GenI surface realiser--- Copyright (C) 2009 Eric Kow------ This program is free software; you can redistribute it and/or--- modify it under the terms of the GNU General Public License--- as published by the Free Software Foundation; either version 2--- of the License, or (at your option) any later version.------ This program is distributed in the hope that it will be useful,--- but WITHOUT ANY WARRANTY; without even the implied warranty of--- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the--- GNU General Public License for more details.------ You should have received a copy of the GNU General Public License--- along with this program; if not, write to the Free Software--- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.--module NLP.GenI.PolarityTypes where--import Data.List ( break )-import qualified Data.Set as Set-import Data.Generics ( Data )-import Data.Typeable ( Typeable )--newtype PolarityKey = PolarityKey { fromPolarityKey :: String } deriving (Show, Eq, Ord, Data, Typeable)---- | 'PolarityAttr' is something you want to perform detect polarities on.-data PolarityAttr = SimplePolarityAttr { spkAtt :: String }- -- | 'RestrictedPolarityKey' @c att@ is a polarity key in which we only pay- --   attention to nodes that have the category @c@.  This makes it possible- --   to have polarities for a just a small subset of nodes- | RestrictedPolarityAttr { _rpkCat :: String, rpkAtt :: String }- deriving (Eq, Ord, Typeable)--readPolarityAttrs :: String -> Set.Set PolarityAttr-readPolarityAttrs = Set.fromList . map helper . words- where-  helper s = case break (== '.') s of-             (a,"") -> SimplePolarityAttr a-             (c,a)  -> RestrictedPolarityAttr c (drop 1 a)--instance Show PolarityAttr where- show (SimplePolarityAttr a) = a- show (RestrictedPolarityAttr c a) = c ++ "." ++ a
+ src/NLP/GenI/Pretty.hs view
@@ -0,0 +1,88 @@+-- GenI surface realiser+-- Copyright (C) 2012 Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.++{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}++-- | This is not a proper pretty printer. I aim is to replace this with a+--   (de-facto) standard library if one should appear+module NLP.GenI.Pretty where++import Data.Text ( Text )+import qualified Data.Text as T++-- | An alternative 'Show' instance (the idea being that we+--   should reserve 'Show' for outputting actual Haskell)+--+--   Minimal implementation is 'pretty' or 'prettyStr'+class Pretty a where+   pretty :: a -> Text+   pretty = T.pack . prettyStr++   prettyStr :: a -> String+   prettyStr = T.unpack . pretty++instance Pretty String where+   prettyStr a = a++instance Pretty Int where+   prettyStr a = show a++instance Pretty Integer where+   prettyStr a = show a++between :: Text -> Text -> Text -> Text+between l r x = l `T.append` x `T.append` r++parens :: Text -> Text+parens = between "(" ")"++squares :: Text -> Text+squares = between "[" "]"++-- | Identical to 'T.append'+(<>) :: Text -> Text -> Text+t1 <> t2 = t1 `T.append` t2++-- | Separated by space unless one of them is empty (in which case just+--   the non-empty one)+(<+>) :: Text -> Text -> Text+t1 <+> t2 | T.null t1 = t2+          | T.null t2 = t1+          | otherwise = t1 `T.append` " " `T.append` t2++-- | I think I want ($+$) here but I'm not sure I understand the+--   documentation from the pretty package.+--+--   @t1 `above` t2@ separates the two by a newline, unless one+--   of them is empty. The vertical equivalent to '(<+>)'+above :: Text -> Text -> Text+above t1 t2 | T.null t1 = t2+            | T.null t2 = t1+            | otherwise = t1 `T.append` "\n" `T.append` t2++-- |+--+-- > prettyCount toBlah ""     (x,1) == "blah"+-- > prettyCount toBlah "foos" (x,1) == "blah"+-- > prettyCount toBlah ""     (x,4) == "blah ×4"+-- > prettyCount toBlah "foos" (x,4) == "blah ×4 foos"+prettyCount :: (a -> Text) -> Text -> (a, Int) -> Text+prettyCount f _  (x, 1) = f x+prettyCount f ts (x, n) = f x <+> count <+> ts+  where+    count = '×' `T.cons` T.pack (show n)
− src/NLP/GenI/Regression.hs
@@ -1,83 +0,0 @@--- GenI surface realiser--- Copyright (C) 2009 Eric Kow------ This program is free software; you can redistribute it and/or--- modify it under the terms of the GNU General Public License--- as published by the Free Software Foundation; either version 2--- of the License, or (at your option) any later version.------ This program is distributed in the hope that it will be useful,--- but WITHOUT ANY WARRANTY; without even the implied warranty of--- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the--- GNU General Public License for more details.------ You should have received a copy of the GNU General Public License--- along with this program; if not, write to the Free Software--- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.---- | Just regression testing of suites---   This can be seen as regression testing of GenI---   and also of grammars using GenI--module NLP.GenI.Regression (regressionGeni) where--import Control.Monad-import Data.IORef(readIORef, modifyIORef)-import Data.List(sort)-import Test.HUnit.Text (runTestTT)-import qualified Test.HUnit.Base as H-import Test.HUnit.Base ((@?))--import NLP.GenI.Btypes-   ( SemInput, showSem-   , TestCase(tcSem, tcName, tcExpected)-   )-import qualified NLP.GenI.Btypes as G-import NLP.GenI.General-  ( fst3,-  )-import NLP.GenI.Geni-import NLP.GenI.Configuration-  ( Params-  , builderType , BuilderType(..)-  )-import qualified NLP.GenI.Builder as B-import NLP.GenI.Simple.SimpleBuilder--regressionGeni :: ProgStateRef -> IO ()-regressionGeni pstRef = do- do pst <- readIORef pstRef-    loadEverything pstRef-    tests <- (mapM toTest) . tsuite $ pst-    runTestTT . (H.TestList) . concat $ tests-    return ()- where-  toTest :: G.TestCase -> IO [H.Test] -- ^ GenI test case to HUnit Tests-  toTest tc = -- run the case, and return a test case for each expected result-   do res <- runOnSemInput pstRef (tcSem tc)-      let sentences = map lemmaSentenceString res-          name = tcName tc-          semStr = showSem . fst3 . tcSem $ tc-          mainMsg  = "for " ++ semStr ++ ",  got no results"-          mainCase = H.TestLabel name-            $ H.TestCase $ (not.null $ sentences) @? mainMsg-          subMsg e = "for " ++ semStr ++ ", failed to get (" ++ e ++ ")"-          subCase e = H.TestLabel name-            $ H.TestCase $ (e `elem` sentences) @? subMsg e-      return $ (mainCase :) $ map subCase (tcExpected tc)---- | Runs a case in the test suite.  If the user does not specify any test---   cases, we run the first one.  If the user specifies a non-existing---   test case we raise an error.-runOnSemInput :: ProgStateRef -> SemInput -> IO [GeniResult]-runOnSemInput pstRef semInput =-  do modifyIORef pstRef (\x -> x{ts = semInput})-     pst <- readIORef pstRef-     let config = pa pst-         go = case builderType config of-                NullBuilder   -> helper B.nullBuilder-                SimpleBuilder -> helper simpleBuilder_2p-                SimpleOnePhaseBuilder -> helper simpleBuilder_1p-     sort `fmap` go-  where-    helper builder = fst3 `fmap` runGeni pstRef builder
+ src/NLP/GenI/Semantics.hs view
@@ -0,0 +1,267 @@+-- GenI surface realiser+-- Copyright (C) 2005-2009 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.++{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE TypeSynonymInstances, MultiParamTypeClasses, FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ViewPatterns #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+module NLP.GenI.Semantics where++import Control.Arrow ( first, (***), (&&&) )+import Control.Applicative ( (<$>) )+import Control.DeepSeq+import Data.Binary+import Data.Function ( on )+import Data.Data+import Data.List ( nub, sortBy, delete, insert )+import Data.Maybe ( isNothing, isJust, mapMaybe, fromMaybe )+import qualified Data.Map as Map+import Data.Text ( Text )+import qualified Data.Text as T++import NLP.GenI.FeatureStructure+import NLP.GenI.GeniShow+import NLP.GenI.General ( histogram )+import NLP.GenI.GeniVal+import NLP.GenI.Pretty++-- handle, predicate, parameters+data Literal gv = Literal+    { lHandle    :: gv+    , lPredicate :: gv+    , lArgs      :: [gv]+    }+ deriving (Eq, Data, Typeable)++instance Ord gv => Ord (Literal gv) where+  compare = compare `on` tucked+    where+      -- treat the handle as an argument+      tucked l = (lPredicate l, lHandle l : lArgs l)++type Sem = [Literal GeniVal]+type LitConstr = (Literal GeniVal, [Text])+type SemInput  = (Sem,Flist GeniVal,[LitConstr])++instance Collectable a => Collectable (Literal a) where+  collect (Literal a b c) = collect a . collect b . collect c++emptyLiteral :: Literal GeniVal+emptyLiteral = Literal mkGAnon mkGAnon []++-- Utility functions++removeConstraints :: SemInput -> SemInput+removeConstraints (x, _, _) = (x, [], [])++-- | default sorting for a semantics+sortSem :: Ord a => [Literal a] -> [Literal a]+sortSem = sortBy compareOnLiteral++compareOnLiteral :: Ord a => Literal a -> Literal a -> Ordering+compareOnLiteral = compare++-- sort primarily putting the ones with the most constants first+-- and secondarily by the number of instances a predicate occurs+-- (if plain string; atomic disjunction/vars treated as infinite)+sortByAmbiguity :: Sem -> Sem+sortByAmbiguity sem = sortBy (flip compare `on` criteria) sem+ where+   criteria  = (constants &&& ambiguity) -- this is reverse sorting+                                         -- so high numbers come first+   ambiguity l = fromMaybe 0 $ do -- Maybe+                   p <- boringLiteral l+                   negate <$> Map.lookup p (literalCount sem)++class HasConstants a where+  constants :: a -> Int++instance HasConstants GeniVal where+  constants g = if isConst2 g then 1 else 0+   where+    isConst2 :: GeniVal -> Bool+    isConst2 x = isJust (gConstraints x) && isNothing (gLabel x)++instance HasConstants a => HasConstants [a] where+  constants = sum . map constants++instance HasConstants (Literal GeniVal) where+  constants (Literal h p args) = constants (h:p:args)++literalCount :: [Literal GeniVal] -> Map.Map Text Int+literalCount = histogram . mapMaybe boringLiteral++boringLiteral :: Literal GeniVal -> Maybe Text+boringLiteral = singletonVal . lPredicate+    -- predicate with a straightfoward constant value+    -- exactly one constraint++-- Traversal++instance DescendGeniVal a => DescendGeniVal (Literal a) where+  descendGeniVal s (Literal h n lp) = Literal (descendGeniVal s h)+                                              (descendGeniVal s n)+                                              (descendGeniVal s lp)++-- Pretty printing++instance Pretty Sem where+   pretty = geniShowText++instance GeniShow Sem where+   geniShowText = squares . T.unwords . map geniShowText++instance Pretty (Literal GeniVal) where+   pretty = geniShowText++instance GeniShow (Literal GeniVal) where+   geniShowText (Literal h p l) =+       mh `T.append` geniShowText p+          `T.append` (parens . T.unwords . map geniShowText $ l)+     where+       mh    = if hideh h then "" else geniShowText h `T.snoc` ':'+       hideh = maybe False isInternalHandle . singletonVal++instance Pretty SemInput where+    pretty = geniShowText++instance GeniShow SemInput where+    geniShowText (sem,icons,lcons) = T.intercalate "\n" . concat $+        [ [semStuff]+        , [ idxStuff | not (null icons) ]+        ]+      where+        semStuff = geniKeyword "semantics"+                 . squares . T.unwords+                 $ map withConstraints sem+        idxStuff = geniKeyword "idxconstraints"+                 . squares+                 $ geniShowText icons+        withConstraints lit =+            case concat [ cs | (p,cs) <- lcons, p == lit ] of+                [] -> geniShowText lit+                cs -> geniShowText lit `T.append` (squares . T.unwords $ cs)++isInternalHandle :: Text -> Bool+isInternalHandle = ("genihandle" `T.isPrefixOf`)++-- ----------------------------------------------------------------------+-- Subsumption+-- ----------------------------------------------------------------------++-- | @x `subsumeSem` y@ returns all the possible ways to unify+--   @x@ with some SUBSET of @y@ so that @x@ subsumes @y@.+--   If @x@ does NOT subsume @y@, we return the empty list.+subsumeSem :: Sem -> Sem -> [(Sem,Subst)]+subsumeSem x y | length x > length y = []+subsumeSem x y =+  map (first sortSem) $ subsumeSemH x y++subsumeSemH :: Sem -> Sem -> [(Sem,Subst)]+subsumeSemH [] [] = [ ([], Map.empty) ]+subsumeSemH _ []  = error "subsumeSemH: got longer list in front"+subsumeSemH []     _  = [ ([], Map.empty) ]+subsumeSemH (x:xs) ys = nub $+ do let attempts = zip ys $ map (subsumeLiteral x) ys+    (y, Just (x2, subst)) <- attempts+    let next_xs = replace subst xs+        next_ys = replace subst $ delete y ys+        prepend = insert x2 *** appendSubst subst+    prepend `fmap` subsumeSemH next_xs next_ys++-- | @p1 `subsumeLiteral` p2@... FIXME+subsumeLiteral :: Literal GeniVal -> Literal GeniVal -> Maybe (Literal GeniVal, Subst)+subsumeLiteral (Literal h1 p1 la1) (Literal h2 p2 la2) =+  if length la1 == length la2+  then do let hpla1 = h1:p1:la1+              hpla2 = h2:p2:la2+          (hpla, sub) <- hpla1 `allSubsume` hpla2+          return (toLiteral hpla, sub)+  else Nothing+ where+  toLiteral (h:p:xs) = Literal h p xs+  toLiteral _ = error "subsumeLiteral.toLiteral"++-- ----------------------------------------------------------------------+-- Unification+-- ----------------------------------------------------------------------++-- We return the list of minimal ways to unify two semantics.+-- By minimal, I mean that any literals that are not the product of a+-- succesful unification really do not unify with anything else.+unifySem :: Sem -> Sem -> [(Sem,Subst)]+unifySem xs ys =+ map (first sortSem) $+ if length xs < length ys+    then unifySemH xs ys+    else unifySemH ys xs++-- list monad for Prolog-style backtracking.+unifySemH :: Sem -> Sem -> [(Sem,Subst)]+unifySemH [] [] = return ([], Map.empty)+unifySemH [] xs = return (xs, Map.empty)+unifySemH xs [] = error $ "unifySem: shorter list should always be in front: " ++ prettyStr xs+unifySemH (x:xs) ys = nub $ do+ let attempts = zip ys $ map (unifyLiteral x) ys+ if all (isNothing . snd) attempts+    then first (x:) `fmap` unifySemH xs ys -- only include x unmolested if no unification succeeds+    else do (y, Just (x2, subst)) <- attempts+            let next_xs = replace subst xs+                next_ys = replace subst $ delete y ys+                prepend = insert x2 *** appendSubst subst+            prepend `fmap` unifySemH next_xs next_ys++unifyLiteral :: Literal GeniVal -> Literal GeniVal -> Maybe (Literal GeniVal, Subst)+unifyLiteral (Literal h1 p1 la1) (Literal h2 p2 la2) =+  if length la1 == length la2+  then do let hpla1 = h1:p1:la1+              hpla2 = h2:p2:la2+          (hpla, sub) <- hpla1 `unify` hpla2+          return (toLiteral hpla, sub)+  else Nothing+ where+  toLiteral (h:p:xs) = Literal h p xs+  toLiteral _ = error "unifyLiteral.toLiteral"++-- ----------------------------------------------------------------------+--+-- ----------------------------------------------------------------------++{-!+deriving instance NFData Literal +deriving instance Binary Literal +!-}++-- GENERATED START++ +instance NFData g => NFData (Literal g) where+        rnf (Literal x1 x2 x3) = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` ()++ +instance Binary g => Binary (Literal g) where+        put (Literal x1 x2 x3)+          = do put x1+               put x2+               put x3+        get+          = do x1 <- get+               x2 <- get+               x3 <- get+               return (Literal x1 x2 x3)+-- GENERATED STOP
+ src/NLP/GenI/Simple/SimpleBuilder.hs view
@@ -0,0 +1,937 @@+-- GenI surface realiser+-- Copyright (C) 2005 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.++{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, LiberalTypeSynonyms, DeriveDataTypeable #-}+{-# LANGUAGE OverloadedStrings #-}+module NLP.GenI.Simple.SimpleBuilder (+   -- Types+   Agenda, AuxAgenda, Chart, SimpleStatus, SimpleState,+   SimpleItem(..),++   -- From SimpleStatus+   simpleBuilder_1p, simpleBuilder_2p, simpleBuilder,+   theAgenda, theHoldingPen, theChart, theResults,+   initSimpleBuilder,+   addToAgenda, addToChart,+   genconfig,+   SimpleGuiItem(..),+   theTrash, step,++   unpackResult,++   -- * Aliases to non-exported functions+   testCanAdjoin, testIapplyAdjNode, testEmptySimpleGuiItem+   )+where++import Control.Arrow (first)+import Control.Monad (when, unless, liftM2)+import Control.Monad.State.Strict (get, put, modify, gets, runState, execStateT)+import Data.Bits+import Data.Generics ( Data )+import Data.List (partition, foldl', sortBy, unfoldr )+import Data.Maybe (isJust, isNothing, mapMaybe, fromMaybe)+import Data.Ord (comparing)+import Data.Text ( Text )+import Data.Tree+import qualified Data.Map as Map+import qualified Data.Text as T++import NLP.GenI.Automaton ( automatonPaths, NFA(..), addTrans )+import NLP.GenI.Builder ( incrCounter, num_iterations, num_comparisons+                        , chart_size, SemBitMap, defineSemanticBits, semToBitVector, bitVectorToSem+                        , DispatchFilter, (>-->), condFilter, FilterStatus(Filtered, NotFiltered)+                        , GenStatus(..),+                        )+import NLP.GenI.Configuration+import NLP.GenI.FeatureStructure ( unifyFeat, Flist )+import NLP.GenI.General ( BitVector, mapMaybeM, mapTree', geniBug, preTerminals, repList )+import NLP.GenI.GeniVal ( GeniVal, replace, DescendGeniVal(..), Subst, appendSubst )+import NLP.GenI.Morphology.Types ( LemmaPlus(..) )+import NLP.GenI.Pretty+import NLP.GenI.Semantics ( sortSem, Sem )+import NLP.GenI.Statistics (Statistics)+import NLP.GenI.Tag+    ( TagElem, TagSite(..), getLexeme, toTagSite+    , tidnum, idname, ttree, ttype, tsemantics+    , detectSites, TagDerivation, DerivationStep(..)+    , plugTree, spliceTree+    , ts_rootFeatureMismatch, ts_synIncomplete, ts_semIncomplete+    , ts_tbUnificationFailure+    )+import NLP.GenI.TreeSchema+    ( Ptype(Initial), GNode(..), NodeName, gnnameIs+    , GType(Other), root, foot )+import qualified NLP.GenI.Builder as B++-- --------------------------------------------------------------------+-- The Builder interface+-- --------------------------------------------------------------------++type SimpleBuilder = B.Builder SimpleStatus SimpleItem Params+simpleBuilder_2p, simpleBuilder_1p :: SimpleBuilder+simpleBuilder_2p = simpleBuilder True+simpleBuilder_1p = simpleBuilder False++simpleBuilder :: Bool -> SimpleBuilder+simpleBuilder twophase = me+ where+  me = B.Builder+   { B.init     = initSimpleBuilder twophase+   , B.step     = if twophase then generateStep_2p else generateStep_1p+   , B.stepAll  = B.defaultStepAll me+   , B.finished = finished twophase+   , B.unpack   = unpackResults.theResults+   , B.partial  = unpackResults.partialResults+   }++-- --------------------------------------------------------------------+-- Key types+-- --------------------------------------------------------------------++type Agenda = [SimpleItem]+type AuxAgenda  = [SimpleItem]+type Chart  = [SimpleItem]+type Trash = [SimpleItem]++data GenerationPhase = SubstitutionPhase+                     | AdjunctionPhase+ deriving (Show)++isAdjunctionPhase :: GenerationPhase -> Bool+isAdjunctionPhase AdjunctionPhase = True+isAdjunctionPhase _ = False++type SimpleState a = B.BuilderState SimpleStatus a++data SimpleStatus = S+  { theAgenda    :: Agenda+  , theHoldingPen :: AuxAgenda+  , theChart     :: Chart+  , theTrash   :: Trash+  , theResults :: [SimpleItem]+  , tsem       :: BitVector+  , step       :: GenerationPhase+  , gencounter :: Integer+  , genconfig  :: Params+  -- we keep a SemBitMap strictly to help display the semantics+  , semBitMap  :: SemBitMap+  }+  -- deriving Show++-- SimpleStatus updaters++assignNewId :: SimpleItem -> SimpleState SimpleItem+assignNewId item = do+  modify $ \s -> s{ gencounter = gencounter s + 1 }+  counter <- gets gencounter+  return $ item { siId = counter }++addToAgenda :: SimpleItem -> SimpleState ()+addToAgenda te = do+  te2 <- assignNewId te+  modify $ \s -> s{theAgenda = te2 : theAgenda s }++updateAgenda :: Agenda -> SimpleState ()+updateAgenda a =+  modify $ \s -> s{theAgenda = a}++addToAuxAgenda :: SimpleItem -> SimpleState ()+addToAuxAgenda te = do+  te2 <- assignNewId te+  modify $ \s -> s { theHoldingPen = te2 : theHoldingPen s }++addToChart :: SimpleItem -> SimpleState ()+addToChart te = do+  modify $ \s -> s { theChart = te:theChart s+                   }+  incrCounter chart_size 1++addToTrash :: SimpleItem -> String -> SimpleState ()+addToTrash te err = do+  disableGui <- gets (hasFlagP DisableGuiFlg . genconfig)+  unless disableGui $+    modify $ \s -> s { theTrash = te2 : theTrash s }+  where+    te2 = modifyGuiStuff (\g -> g { siDiagnostic = err : siDiagnostic g }) te++addToResults :: SimpleItem -> SimpleState ()+addToResults te =+  modify $ \s -> s { theResults = te : theResults s }++-- ----------------------------------------------------------------------+-- SimpleItem+-- ----------------------------------------------------------------------++data SimpleItem = SimpleItem+ { siId        :: ChartId+ --+ , siSubstnodes :: [NodeName]+ , siAdjnodes   :: [NodeName]+ --+ , siSemantics :: BitVector+ , siPolpaths  :: BitVector+ -- for generation sans semantics+ -- , siAdjlist :: [(String,Integer)] -- (node name, auxiliary tree id)+ , siNodes   :: [GNode GeniVal]    -- ^ actually a set+ , siDerived :: Tree Text+ , siRoot_    :: NodeName+ , siFoot_    :: Maybe NodeName+ --+ , siPendingTb :: [NodeName] -- only for one-phase+ -- how was this item produced?+ , siDerivation :: TagDerivation+ -- for the debugger only+ , siGuiStuff :: SimpleGuiItem+ } -- deriving (Show)+++lookupOrBug :: Text -> SimpleItem -> NodeName -> GNode GeniVal+lookupOrBug fnname item k =+        case filter (gnnameIs k) (siNodes item) of+          []   -> geniBug $ T.unpack fnname ++ ": could not find node " ++ T.unpack k+          [gn] -> gn+          _    -> geniBug $ T.unpack fnname ++ ": more than one node named " ++ T.unpack k++siRoot :: SimpleItem -> TagSite+siRoot x = toTagSite . lookupOrBug "siRoot" x $ siRoot_ x++siFoot :: SimpleItem -> Maybe TagSite+siFoot x = (toTagSite . lookupOrBug "siFoot" x) `fmap` siFoot_ x++instance DescendGeniVal (Text, B.UninflectedDisjunction) where+  descendGeniVal m (s,d) = (s, descendGeniVal m d)++-- | Things whose only use is within the graphical debugger+data SimpleGuiItem = SimpleGuiItem+ { siHighlight :: [Text] -- ^ nodes to highlight+ -- if there are things wrong with this item, what?+ , siDiagnostic :: [String]+ , siFullSem :: Sem+ , siIdname  :: Text+ } deriving (Data, Typeable)++emptySimpleGuiItem :: SimpleGuiItem+emptySimpleGuiItem = SimpleGuiItem [] [] [] ""++testEmptySimpleGuiItem :: SimpleGuiItem+testEmptySimpleGuiItem = emptySimpleGuiItem++modifyGuiStuff :: (SimpleGuiItem -> SimpleGuiItem) -> SimpleItem -> SimpleItem+modifyGuiStuff fn i = i { siGuiStuff = fn . siGuiStuff $ i }++type ChartId = Integer++instance DescendGeniVal SimpleItem where+  descendGeniVal s i = s `seq` i `seq`+    i { siNodes   = descendGeniVal s (siNodes i) }++{-# INLINE closedAux #-}++-- | True if the chart item has no open substitution nodes+closed :: SimpleItem -> Bool+closed = null.siSubstnodes++-- | True if the chart item is an auxiliary tree+aux :: SimpleItem -> Bool+aux = isJust . siFoot++-- | True if both 'closed' and 'aux' are True+closedAux :: SimpleItem -> Bool+closedAux x = aux x && closed x++adjdone :: SimpleItem -> Bool+adjdone = null.siAdjnodes++siInitial :: SimpleItem -> Bool+siInitial =  isNothing . siFoot++-- --------------------------------------------------------------------+-- Initialisation+-- --------------------------------------------------------------------++-- | Creates an initial SimpleStatus.+initSimpleBuilder ::  Bool -> B.Input -> Params -> (SimpleStatus, Statistics)+initSimpleBuilder twophase input config =+  let disableGui = hasFlagP DisableGuiFlg config+      cands   = map (initSimpleItem disableGui bmap) $ B.inCands input+      (sem,_,_) = B.inSemInput input+      bmap    = defineSemanticBits sem+      -- FIXME: I don't know if this matters for one-phase+      -- because of on-the-fly tb unification (in 2p), we+      -- need an initial tb step that only addresses the+      -- nodes with null adjunction constraints+      simpleDp = if twophase then simpleDispatch_2p else simpleDispatch_1p+      initialDp = dpTbNaFailure >--> dpTbFailure >--> simpleDp+      --+      initS = S{ theAgenda    = []+               , theHoldingPen = []+               , theChart     = []+               , theTrash     = []+               , theResults   = []+               , semBitMap = bmap+               , tsem      = semToBitVector bmap sem+               , step     =  SubstitutionPhase+               , gencounter = 0+               , genconfig  = config }+      --+  in B.unlessEmptySem input config $+     runState (execStateT (mapM initialDp cands) initS) (B.initStats config)+++initSimpleItem :: Bool -- ^ disable gui+               -> SemBitMap -> (TagElem, BitVector) -> SimpleItem+initSimpleItem disableGui bmap (teRaw,pp) =+ let (te,tlite) = renameNodesWithTidnum teRaw in+ case detectSites (ttree te) of+ (snodes,anodes,nullAdjNodes) -> SimpleItem+  { siId        = tidnum te+  , siSemantics = semToBitVector bmap (tsemantics te)+  , siSubstnodes = snodes+  , siAdjnodes   = anodes+  , siPolpaths  = pp+  -- for generation sans semantics+  -- , siAdjlist = []+  , siNodes = flatten.ttree $ te+  , siDerived = tlite+  , siRoot_ = gnname . root $ theTree+  , siFoot_ = if ttype te == Initial then Nothing else Just . gnname . foot $ theTree+  , siDerivation = [ InitStep (gorigin . root $ theTree) ]+  -- note: see comment in initSimpleBuilder re: tb unification+  , siPendingTb = nullAdjNodes+  --+  , siGuiStuff = if disableGui then emptySimpleGuiItem else initSimpleGuiItem te+  }+  where theTree = ttree te++initSimpleGuiItem :: TagElem -> SimpleGuiItem+initSimpleGuiItem te = SimpleGuiItem+ { siHighlight = []+ , siDiagnostic = []+ , siFullSem = tsemantics te+ , siIdname = idname te }++renameNodesWithTidnum :: TagElem -> (TagElem, Tree NodeName)+renameNodesWithTidnum te =+    ( te { ttree = mapTree' renameNode theTree }+    , mapTree' newName theTree+    )+  where+    theTree = ttree te+    renameNode n = n { gnname = newName n }+    newName n = gnname n `T.append` "-" `T.append` tidstr te+    tidstr    = T.pack . show . tidnum++-- --------------------------------------------------------------------+-- Generate+-- --------------------------------------------------------------------++-- One-phase generation++generateStep_1p :: SimpleState ()+generateStep_1p =+ do isDone <- gets (null.theAgenda)+    let dispatch = mapM simpleDispatch_1p+    if isDone+       then return ()+       else do incrCounter num_iterations 1+               given <- selectGiven+               -- do both substitution and adjunction+               _ <- applySubstitution1p given >>= dispatch+               _ <- passiveAdjunction1p given >>= dispatch+               _ <- activeAdjunction1p  given >>= dispatch+               _ <- sansAdjunction1p    given >>= dispatch+               -- determine which of the res should go in the agenda+               -- (monadic state) and which should go in the result (res')+               addToChart given++-- Two-phase generation++generateStep_2p :: SimpleState ()+generateStep_2p = do+  nir     <- gets (null.theAgenda)+  curStep <- gets step+  case curStep of+   SubstitutionPhase -> if nir then switchToAux else generateStep_2p_sub+   AdjunctionPhase   -> if nir then return ()   else generateStep_2p_adj++generateStep_2p_sub :: SimpleState ()+generateStep_2p_sub =+  do incrCounter num_iterations 1+     -- choose an item from the agenda+     given <- selectGiven+     res <- applySubstitution given+     mapM_ simpleDispatch_2p res+     -- put the given into the chart untouched+     addToChart given++generateStep_2p_adj :: SimpleState ()+generateStep_2p_adj =+  do incrCounter num_iterations 1+     -- choose an item from the agenda+     given <- selectGiven+     res <- liftM2 (++) (applyAdjunction2p given) (sansAdjunction2p given)+     mapM_ simpleDispatch_2p_adjphase res+     when (adjdone given) $ trashIt given++-- Helpers for the generateSteps++trashIt :: SimpleItem -> SimpleState ()+trashIt item =+ do disableGui <- gets (hasFlagP DisableGuiFlg . genconfig)+    unless disableGui $ do+    s <- get+    let bmap = semBitMap s+        itemSem = siSemantics item+        inputSem = tsem s+        reason = if inputSem == itemSem+                    then "unknown reason!"+                    else ts_semIncomplete $ bitVectorToSem bmap $ inputSem `xor` itemSem+    addToTrash item reason++-- | Arbitrarily selects and removes an element from the agenda and+--   returns it.+selectGiven :: SimpleState SimpleItem+selectGiven = do+  agenda <- gets theAgenda+  case agenda of+   [] -> geniBug "null agenda in selectGiven"+   (a:atail) -> updateAgenda atail >> return a++-- Switching phases++switchToAux :: SimpleState ()+switchToAux = do+  st <- get+  let oldAuxTrees = theHoldingPen st+      -- You might be wondering why we ignore the auxiliary trees in the+      -- chart; this is because all the syntactically complete auxiliary+      -- trees have already been filtered away by calls to classifyNew+      initialT  = filter siInitial (theChart st)+      (compT1, incompT1) = partition (null.siSubstnodes) initialT+      (auxTrees, compT2) =+        ( mapMaybe (detectNa oldAuxTrees) oldAuxTrees+        , mapMaybe (detectNa auxTrees) compT1 )+      (compT3, incompT3) = semfilter (tsem st) auxTrees compT2+      --+      compT = compT3+  put st{ theAgenda = []+        , theHoldingPen = []+        , theChart = auxTrees+        , step = AdjunctionPhase }+  mapM_ simpleDispatch_2p_adjphase compT+  -- toss the syntactically incomplete stuff in the trash+  mapM_ (\t -> addToTrash t ts_synIncomplete) incompT1+  mapM_ (\t -> addToTrash t "sem-filtered") incompT3++-- Completion++finished :: Bool -> SimpleStatus -> GenStatus+finished twophase st+  | reallyDone   = B.Finished+  | atMaxResults = B.Finished+  | atMaxSteps   = B.Error $ "Max steps exceeded" <+> parens (pretty maxSteps)+  | otherwise    = B.Active+ where+  reallyDone   = null (theAgenda st) && (not twophase || isAdjunctionPhase (step st)) +  atMaxResults = maybeIf (<= fromIntegral (length (theResults st))) $ getFlagP MaxResultsFlg (genconfig st)+  atMaxSteps   = maybeIf (<  gencounter st) mMaxSteps+  mMaxSteps    = getFlagP MaxStepsFlg (genconfig st)+  maxSteps     = fromMaybe (error "get maxsteps") mMaxSteps+  maybeIf bf = maybe False bf++-- SemFilter Optimisation++semfilter :: BitVector -> [SimpleItem] -> [SimpleItem] -> ([SimpleItem], [SimpleItem])+semfilter inputsem auxs initial =+  let auxsem x = foldl' (.|.) 0 [ siSemantics a | a <- auxs, siPolpaths a .&. siPolpaths x /= 0 ]+      -- lite, here, means sans auxiliary semantics+      notjunk x = (siSemantics x) .&. inputsemLite == inputsemLite+                  where inputsemLite = inputsem `xor` (auxsem x)+      -- note that we can't just compare against siSemantics because+      -- that would exclude trees that have stuff in the aux semantics+      -- which would be overzealous+  in partition notjunk initial++-- --------------------------------------------------------------------+-- Substitution+-- --------------------------------------------------------------------++applySubstitution :: SimpleItem -> SimpleState ([SimpleItem])+applySubstitution item =+ do gr <- lookupChart item+    active  <- mapM (\x -> iapplySubst True item x) gr+    passive <- mapM (\x -> iapplySubst True x item) gr+    let res = concat $ active ++ passive+    incrCounter num_comparisons (2 * (length gr))+    return res++applySubstitution1p :: SimpleItem -> SimpleState ([SimpleItem])+applySubstitution1p item =+ do gr <- lookupChart item+    active  <- if adjdone item then return []+               else mapM (\x -> iapplySubst False item x) gr+    passive <- mapM (\x -> iapplySubst False x item) $ filter adjdone gr+    let res = concat $ active ++ passive+    incrCounter num_comparisons (2 * (length gr))+    return res++-- | Note: returns ONE possible substitution (the head node)+--   of the first in the second.  As all substitutions nodes should+--   be substituted we force substitution in order.+iapplySubst :: Bool -> SimpleItem -> SimpleItem -> SimpleState [SimpleItem]+iapplySubst twophase item1 item2 | siInitial item1 && closed item1 = {-# SCC "applySubstitution" #-}+ case siSubstnodes item2 of+ [] -> return []+ (shead : stail) ->+  let doIt =+       do -- Maybe monad+          let (TagSite n  fu fd nOrigin) = toTagSite (lookupOrBug "iapplySubst" item2 shead)+              (TagSite rn ru rd rOrigin) = siRoot item1+          (newU, subst1) <- unifyFeat ru fu+          (newD, subst2) <- unifyFeat (replace subst1 rd)+                                      (replace subst1 fd)+          let subst = appendSubst subst1 subst2+              -- gui stuff+              newRoot g = g { gup = newU, gdown = newD, gtype = Other }+          let pending = if twophase then []+                        else rn : (siPendingTb item1 ++ siPendingTb item2)+          let item1g = item1 { siNodes = repList (gnnameIs rn) newRoot (siNodes item1) }+          return $! replace subst $ combineSimpleItems [rn] item1g $+                     item2 { siSubstnodes = stail ++ (siSubstnodes item1)+                           , siAdjnodes   = siAdjnodes item1 ++ siAdjnodes item2+                           , siDerived    = plugTree (siDerived item1) n (siDerived item2)+                           , siDerivation = addToDerivation SubstitutionStep (item1, rOrigin) (item2,nOrigin,n)+                           , siPendingTb  = pending+                           }+  in case doIt of+     Nothing -> return []+     Just x  -> do incrCounter "substitutions" 1+                   return [x]+iapplySubst _ _ _ = return []++-- --------------------------------------------------------------------+-- Adjunction+-- ---------------------------------------------------------------++applyAdjunction2p :: SimpleItem -> SimpleState ([SimpleItem])+applyAdjunction2p item = {-# SCC "applyAdjunction2p" #-}+ do gr <-lookupChart item+    incrCounter num_comparisons (length gr)+    mapMaybeM (\a -> tryAdj True a item) gr++passiveAdjunction1p :: SimpleItem -> SimpleState [SimpleItem]+passiveAdjunction1p item | closed item && siInitial item =+  do gr <- lookupChart item+     mapMaybeM (\a -> tryAdj False a item) $ filter validAux gr+passiveAdjunction1p _ = return []++activeAdjunction1p :: SimpleItem -> SimpleState [SimpleItem]+activeAdjunction1p item | validAux item =+  do gr <- lookupChart item+     mapMaybeM (\p -> tryAdj False item p) $ filter (\x -> siInitial x && closed x) gr+activeAdjunction1p _ = return []++validAux :: SimpleItem -> Bool+validAux t = closedAux t && adjdone t++tryAdj :: Bool -> SimpleItem -> SimpleItem -> SimpleState (Maybe SimpleItem)+tryAdj twophase aItem pItem =+ do case iapplyAdjNode twophase aItem pItem of+     Just x  -> do incrCounter "adjunctions" 1+                   return $ Just x+     Nothing -> return Nothing++-- | Ignore the next adjunction node+sansAdjunction1p, sansAdjunction2p :: SimpleItem -> SimpleState [SimpleItem]+sansAdjunction1p item | closed item =+ case siAdjnodes item of+ [] -> return []+ (ahead : atail) ->+   return $ [item { siAdjnodes = atail+                  , siPendingTb = ahead : (siPendingTb item) } ]+sansAdjunction1p _ = return []++-- | Ignore the next adjunction node+sansAdjunction2p item | closed item =+ case siAdjnodes item of+ [] -> return []+ (ahead : atail) -> do+  let (TagSite gn t b _) = toTagSite (lookupOrBug "sansAdjunction2p" item ahead)+  -- do top/bottom unification on the node+  case unifyFeat t b of+   Nothing ->+     do addToTrash (modifyGuiStuff (\g -> g { siHighlight = [gn] }) item)+                   ts_tbUnificationFailure+        return []+   Just (tb,s) ->+     let item1 = constrainAdj gn tb item+     in return $! [replace s $! item1 { siAdjnodes = atail }]+sansAdjunction2p _ = return []++iapplyAdjNode :: Bool -> SimpleItem -> SimpleItem -> Maybe SimpleItem+iapplyAdjNode twophase aItem pItem = {-# SCC "iapplyAdjNode" #-}+ case siAdjnodes pItem of+ [] -> Nothing+ (pHead : pTail) -> do+  -- let's go!+  let pSite = toTagSite (lookupOrBug "iapplyAdjNode" pItem pHead)+  (anr, anf, subst12) <- canAdjoin aItem pSite+  let r_name = siRoot_ aItem+      r = siRoot aItem+  f <- siFoot aItem+  let an_name = tsName pSite+      -- the new adjunction nodes+      aItem2 = aItem { siNodes = map (setSites anr) (siNodes aItem)  }+        where+          setSites (TagSite n u d _) gn =+            if gnname gn == n then gn { gup = u, gdown = d } else gn+      rawCombined =+        combineSimpleItems [tsName r, an_name] aItem2 $ pItem+               { siAdjnodes = pTail ++ siAdjnodes aItem+               , siDerived = spliceTree (tsName f) (siDerived aItem) an_name (siDerived pItem)+               , siDerivation = addToDerivation AdjunctionStep (aItem,tsOrigin r) (pItem,tsOrigin pSite,an_name)+               -- , siAdjlist = (n, (tidnum te1)):(siAdjlist item2)+               -- if we adjoin into the root, the new root is that of the aux+               -- tree (affects 1p only)+               , siRoot_ = if isRootOf pItem an_name then r_name else siRoot_ pItem+               , siPendingTb =+                  if twophase then []+                  else tsName f : siPendingTb pItem ++ siPendingTb aItem+               }+      -- one phase = postpone tb unification+      -- two phase = do tb unification on the fly+      finalRes1p = return $ replace subst12 rawCombined+      finalRes2p =+       do -- tb on the former foot+          tbRes <- unifyFeat (tsUp anf) (tsDown anf)+          let (anf_tb, subst3) = tbRes+              myRes = constrainAdj an_name anf_tb res'+          -- apply the substitutions+              res' = replace (appendSubst subst12 subst3) rawCombined+          return myRes+  -- ---------------+  if twophase then finalRes2p else finalRes1p++testIapplyAdjNode :: Bool -> SimpleItem -> SimpleItem -> Maybe SimpleItem+testIapplyAdjNode = iapplyAdjNode++canAdjoin :: SimpleItem -> TagSite -> Maybe (TagSite, TagSite, Subst)+canAdjoin aItem pSite = do+  -- let's go!+  let r = siRoot aItem -- auxiliary tree, eh?+  f <- siFoot aItem -- should really be an error if fails+  (anr_up',  subst1)  <- unifyFeat (tsUp r) (tsUp pSite)+  (anf_down, subst2)  <- unifyFeat (replace subst1 $ tsDown f) (replace subst1 $ tsDown pSite)+  let -- combined substitution list and success condition+      subst12 = appendSubst subst1 subst2+      anr = replace subst12 $ r { tsUp = anr_up' } --  resulting node based on the root node of the aux tree+      anf = replace subst12 $ f { tsDown = anf_down } --  resulting node based on the foot node of the aux tree+  return (anr, anf, subst12)++testCanAdjoin :: SimpleItem -> TagSite -> Maybe (TagSite, TagSite, Subst)+testCanAdjoin = canAdjoin++detectNa :: [SimpleItem] -- ^ aux trees+         -> SimpleItem   -- ^ me+         -> Maybe SimpleItem+detectNa rawAux i = helper (map look (siAdjnodes i)) Map.empty []+ where+  look = toTagSite . lookupOrBug "detectNa" i+  compatAux = filterCompatible i rawAux+  helper []     s acc = Just $ replace s $ i { siAdjnodes = acc }+  helper (t:ts) s acc =+    let hasAdj = any isJust $ map (\a -> canAdjoin a t) compatAux+    in case (snd `fmap` unifyFeat (tsUp t) (tsDown t)) of+        Just s2 -> if hasAdj+                   then helper ts s (tsName t : acc)+                   else helper (replace s2 ts) (appendSubst s s2) acc+        Nothing -> if hasAdj+                   then helper ts s (tsName t : acc)+                   else Nothing++-- --------------------------------------------------------------------+-- Helper functions for operations+-- --------------------------------------------------------------------++isRootOf :: SimpleItem -> Text -> Bool+isRootOf item n = n == siRoot_ item++-- | Retrieves a list of trees from the chart which could be combined with the given agenda tree.+-- The current implementation searches for trees which+--  * do not have overlapping semantics with the given+--  * are on the some of the same polarity automaton paths as the+--    current agenda item+lookupChart :: SimpleItem -> SimpleState [SimpleItem]+lookupChart given = gets (filterCompatible given . theChart)++filterCompatible :: SimpleItem -> [SimpleItem] -> [SimpleItem]+filterCompatible given chart =+  [ i | i <- chart+      -- should be on the same polarity path (chart sharing)+      , (siPolpaths i) .&. gpaths /= 0+      -- semantics should not be overlapping+      && (siSemantics i .&. gsem ) == 0+  ]+ where+  gpaths = siPolpaths given+  gsem   = siSemantics given++-- | Helper function for when chart operations succeed.+combineSimpleItems :: [NodeName] -- ^ nodes to highlight+                   -> SimpleItem -> SimpleItem -> SimpleItem+combineSimpleItems hi item1 item2 = {-# SCC "combineSimpleItems" #-}+  item2 { siSemantics = siSemantics item1 .|. siSemantics item2+        , siPolpaths  = siPolpaths  item1 .&. siPolpaths  item2+        , siGuiStuff  = combineSimpleGuiItems hi (siGuiStuff item1) (siGuiStuff item2)+        , siNodes     = siNodes item1 ++ siNodes item2+        }++combineSimpleGuiItems :: [NodeName]+                      -> SimpleGuiItem -> SimpleGuiItem -> SimpleGuiItem+combineSimpleGuiItems hi item1 item2 =+ item2 { siFullSem = sortSem $ siFullSem item1 ++ siFullSem item2+       , siDiagnostic = siDiagnostic item1 ++ siDiagnostic item2+       , siHighlight = hi+       }++constrainAdj :: Text -> Flist GeniVal -> SimpleItem -> SimpleItem+constrainAdj gn newT g =+  g { siNodes = repList (gnnameIs gn) fixIt (siNodes g) }+  where fixIt n = n { gup = newT, gdown = [], gaconstr = True }++-- Derivation trees++addToDerivation :: (Text -> Text -> Text -> DerivationStep)+                -> (SimpleItem, Text)+                -> (SimpleItem, Text, Text)+                -> TagDerivation+addToDerivation op (tc,tcOrigin) (tp,tpOrigin,tpSite) =+  let hp = siDerivation tp+      hc = filter (not . isInit) (siDerivation tc)+      newnode = op tcOrigin tpOrigin tpSite+  in newnode:hp++hc+ where+  isInit :: DerivationStep -> Bool+  isInit (InitStep _) = True+  isInit _ = False++-- --------------------------------------------------------------------+-- Dispatching new results+-- --------------------------------------------------------------------++type SimpleDispatchFilter = DispatchFilter SimpleState SimpleItem++simpleDispatch_2p :: SimpleDispatchFilter+simpleDispatch_2p =+ simpleDispatch (dpRootFeatFailure >--> dpToResults)+                (dpAux >--> dpToAgenda)++simpleDispatch_2p_adjphase :: SimpleDispatchFilter+simpleDispatch_2p_adjphase =+ simpleDispatch (dpRootFeatFailure >--> dpToResults)+                dpToAgenda++simpleDispatch_1p :: SimpleDispatchFilter+simpleDispatch_1p =+ simpleDispatch (dpRootFeatFailure >--> dpTbFailure >--> dpToResults)+                dpToAgenda++simpleDispatch :: SimpleDispatchFilter -> SimpleDispatchFilter -> SimpleDispatchFilter+simpleDispatch resFilter nonResFilter item =+ do inputsem <- gets tsem+    let synComplete x = siInitial x && closed x && adjdone x+        semComplete x = inputsem == siSemantics x+        isResult x = synComplete x && semComplete x+    condFilter isResult resFilter nonResFilter item++dpAux, dpToAgenda :: SimpleDispatchFilter+dpTbFailure, dpToResults :: SimpleDispatchFilter+dpToTrash :: String -> SimpleDispatchFilter++dpToAgenda x  = addToAgenda x  >> return Filtered+dpToResults x = addToResults x >> return Filtered+dpToTrash m x = addToTrash x m >> return Filtered++dpAux item =+  if closedAux item+  then addToAuxAgenda item >> return Filtered+  else return (NotFiltered item)++{-+-- | Dispatches to the trash and returns Nothing if there is a tree+--   size limit in effect and the item is over that limit.  The+--   tree size limit is used in 'IgnoreSemantics' mode.+dpTreeLimit item =+ do config <- gets genconfig+    case maxTrees config of+     Nothing  -> return $ Just item+     Just lim -> if (length.snd.siDerivation) item > lim+                 then do addToTrash item (ts_overnumTrees lim)+                         return Nothing+                 else return $ Just item+   where ts_overnumTrees l = "Over derivation size of " ++ (show l)+-}++dpTbNaFailure :: SimpleDispatchFilter+dpTbNaFailure item =+ case tbUnifyNaNodes (siNodes item) of+   Nothing      -> dpToTrash ("top-bottom unification failure in NA nodes") item+   Just (ns2,s) -> return . NotFiltered . replace s $ item { siNodes = ns2 }++-- | This is only used for the one-phase algorithm+dpTbFailure item =+ return (if tbUnifyTree item then NotFiltered item else Filtered)++-- | If the item (ostensibly a result) does not have the correct root+--   category, return Nothing; otherwise return Just item+dpRootFeatFailure :: SimpleDispatchFilter+dpRootFeatFailure item =+ do config <- gets genconfig+    let rootFeat = getListFlagP RootFeatureFlg config+        (TagSite _ top _ _) = siRoot item+    case unifyFeat rootFeat top of+      Nothing ->+        dpToTrash (ts_rootFeatureMismatch rootFeat) item+      Just (_, s) ->+        return . NotFiltered $ replace s item++-- --------------------------------------------------------------------+-- Top and bottom unification+-- --------------------------------------------------------------------++tbUnifyNaNodes :: [GNode GeniVal] -> Maybe ([GNode GeniVal], Subst)+tbUnifyNaNodes [] = Just ([], Map.empty)+tbUnifyNaNodes (n:ns) =+ if gaconstr n+    then do (ud, sub) <- unifyFeat (gup n) (gdown n)+            let n2 = n { gup = ud, gdown = [] }+            (ns2, sub2) <- tbUnifyNaNodes (replace sub ns)+            return (n2:ns2, sub `appendSubst` sub2)+    else first (n:) `fmap` tbUnifyNaNodes ns++type TbEither = Either Text Subst+tbUnifyTree :: SimpleItem -> Bool+tbUnifyTree item = {-# SCC "tbUnifyTree" #-}+  case foldl' tbUnifyNode (Right Map.empty) pending of+    Left  _ -> False+    Right _ -> True+  where+   pending = map (toTagSite . lookupOrBug "tbUnifyTree" item) (siPendingTb item)++tbUnifyNode :: TbEither -> TagSite -> TbEither+tbUnifyNode (Right pending) rawSite =+  -- apply pending substitutions+  case replace pending rawSite of+  (TagSite name up down _) ->+    -- check top/bottom unification on this node+    case unifyFeat up down of+    -- stop all future iterations+    Nothing -> Left name+    -- apply any new substutions to the whole tree+    Just (_,sb) -> Right (appendSubst pending sb)++-- if earlier we had a failure, don't even bother+tbUnifyNode (Left n) _ = Left n++-- --------------------------------------------------------------------+-- Unpacking the results+-- --------------------------------------------------------------------++unpackResults :: [SimpleItem] ->  [B.Output]+unpackResults = concatMap unpackResult++--Change, instead of returning the features of the parent node for every leaf, return:+--      -the features of the parent node when the leaf doesn't have features (top and bottom feature structure empty)+--      -the features of the node in case it has (in this case return the unification of top and bottom features).+unpackResult :: SimpleItem -> [B.Output]+unpackResult item =+  let look = lookupOrBug "unpackResult" item+      toUninflectedDisjunction (pt,t) =+        --B.UninflectedDisjunction (getLexeme (look t)) (gup (look pt)) +        B.UninflectedDisjunction (getLexeme (look t))+                                 (gup . look $ if emptyFeatureStr (look t) then pt else t)++      derivation = siDerivation item+      paths = automatonPaths . listToSentenceAut .  map toUninflectedDisjunction . preTerminals . siDerived $ item+ in map (\p -> (siId item, p, derivation)) paths++emptyFeatureStr :: GNode GeniVal -> Bool+emptyFeatureStr n= null (gdown n) && null (gup n)++-- Sentence automata++listToSentenceAut :: [ B.UninflectedDisjunction ] -> B.SentenceAut+listToSentenceAut nodes =+  let theStart  = 0+      theEnd = length nodes - 1+      theStates = [theStart..theEnd]+      --+      emptyAut = NFA+        { startSt     = theStart+        , isFinalSt   = Nothing+        , finalStList = [theEnd]+        , states      = [theStates]+        , transitions = Map.empty }+      -- create a transition for each lexeme in the node to the+      -- next state...+      helper :: (Int, B.UninflectedDisjunction) -> B.SentenceAut -> B.SentenceAut+      helper (current, B.UninflectedDisjunction lemmas features) aut =+        foldl' addT aut lemmas+        where+          addT a t = addTrans a current (Just (LemmaPlus t features)) next+          next = current + 1+      --+  in foldr helper emptyAut (zip theStates nodes)++-- --------------------------------------------------------------------+-- Partial results+-- --------------------------------------------------------------------++partialResults :: SimpleStatus -> [SimpleItem]+partialResults st = unfoldr getNext 0+ where+  inputsem = tsem st+  trash  = theTrash st+  trashC = sortBy (comparing $ negate . fst) $+           map (\t -> (coverage inputsem t, t)) trash+  getNext sem = case getItems sem of+                     []     -> Nothing+                     (it:_) -> Just (it, siSemantics it .|. sem)+  getItems sem = [ i | (_,i) <- trashC, siSemantics i .&. sem == 0 ]++coverage :: BitVector -> SimpleItem -> Int+coverage sem it = countBits (sem .&. siSemantics it)++countBits :: Bits a => a -> Int+countBits 0  = 0+countBits bs = if testBit bs 0 then 1 + next else next+  where next = countBits (shiftR bs 1)++-- --------------------------------------------------------------------+-- Performance+-- --------------------------------------------------------------------++{-+instance NFData SimpleItem where+  rnf (SimpleItem x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 x13+      ) = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` rnf x4 `seq` rnf x5 `seq` rnf x6+                 `seq` rnf x7 `seq` rnf x8 `seq` rnf x9 `seq` rnf x10 `seq` rnf x11+                 `seq` rnf x11 `seq` rnf x12 `seq` rnf x13+                 `seq` rnf x14+-}
− src/NLP/GenI/Simple/SimpleBuilder.lhs
@@ -1,1225 +0,0 @@-% GenI surface realiser-% Copyright (C) 2005 Carlos Areces and Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.--\chapter{SimpleBuilder}-\label{cha:SimpleBuilder}--A SimpleBuilder is a Builder which constructs derived trees using a-simple agenda control mechanism and two-phase realisation (substitution-before adjunction).  There is no packing strategy whatsoever; each chart-item is a derived tree.--\begin{code}-{-# OPTIONS_GHC -fglasgow-exts -fno-warn-orphans #-}-{-# LANGUAGE LiberalTypeSynonyms, TemplateHaskell #-}-module NLP.GenI.Simple.SimpleBuilder (-   -- Types-   Agenda, AuxAgenda, Chart, SimpleStatus, SimpleState,-   SimpleItem(..),--   -- From SimpleStatus-   simpleBuilder_1p, simpleBuilder_2p, simpleBuilder,-   theAgenda, theHoldingPen, theChart, theResults,-   initSimpleBuilder,-   addToAgenda, addToChart,-   genconfig,-   SimpleGuiItem(..),-   theTrash, step,--   unpackResult,-   )-where-\end{code}---\ignore{-\begin{code}-import Control.Arrow ( second )-import Control.Monad (when, unless, liftM2)-import Control.Monad.State.Strict-  (get, put, modify, gets, runState, execStateT)--import Data.List (partition, delete, foldl')-import Data.Maybe (isJust, isNothing, mapMaybe)-import Data.Ord (comparing)-import Data.Bits-import qualified Data.Map as Map-import Data.Tree--import Data.Generics ( Data )-import Data.Generics.PlateDirect--import NLP.GenI.Statistics (Statistics)--import NLP.GenI.Automaton ( automatonPaths, NFA(..), addTrans )-import NLP.GenI.Btypes-  ( Ptype(Initial)-  , GeniVal-  , replace, DescendGeniVal(..)-  , GNode(..), NodeName-  , root, foot-  , plugTree, spliceTree-  , unifyFeat, Flist, Subst, mergeSubst-  )-import NLP.GenI.Builder (-    incrCounter, num_iterations, num_comparisons, chart_size,-    SemBitMap, defineSemanticBits, semToBitVector, bitVectorToSem,-    DispatchFilter, (>-->), condFilter, nullFilter,-    semToIafMap, IafAble(..), IafMap, fromUniConst, getIdx,-    recalculateAccesibility, iafBadSem, ts_iafFailure,-    LemmaPlus(..),-    )-import qualified NLP.GenI.Builder as B--import NLP.GenI.Tags (TagElem, TagSite(..),-             tagLeaves, tidnum,-             ttree, ttype, tsemantics,-             detectSites,-             TagDerivation, DerivationStep(..),-             ts_rootFeatureMismatch,-            )-import NLP.GenI.Configuration-import NLP.GenI.General- ( BitVector, mapMaybeM, mapTree', geniBug, preTerminals, )--import NLP.GenI.Btypes ( GType(Other), sortSem, Sem, gnnameIs )-import NLP.GenI.General ( repList, )-import NLP.GenI.Tags ( idname,-    ts_synIncomplete, ts_semIncomplete, ts_tbUnificationFailure,-    )--import Data.List ( sortBy, unfoldr )-\end{code}-}--% ---------------------------------------------------------------------\section{The Builder interface}-% ----------------------------------------------------------------------Here is our implementation of Builder.--\begin{code}-type SimpleBuilder = B.Builder SimpleStatus SimpleItem Params-simpleBuilder_2p, simpleBuilder_1p :: SimpleBuilder-simpleBuilder_2p = simpleBuilder True-simpleBuilder_1p = simpleBuilder False--simpleBuilder :: Bool -> SimpleBuilder-simpleBuilder twophase = B.Builder-  { B.init     = initSimpleBuilder twophase-  , B.step     = if twophase then generateStep_2p else generateStep_1p-  , B.stepAll  = B.defaultStepAll (simpleBuilder twophase)-  , B.finished = \s -> (null.theAgenda) s && (not twophase || isAdjunctionPhase (step s))-  , B.unpack   = unpackResults.theResults-  , B.partial  = unpackResults.partialResults-  }-\end{code}--% ---------------------------------------------------------------------\section{Key types}-% ----------------------------------------------------------------------\begin{code}-type Agenda = [SimpleItem]-type AuxAgenda  = [SimpleItem]-type Chart  = [SimpleItem]-type Trash = [SimpleItem]--data GenerationPhase = SubstitutionPhase-                     | AdjunctionPhase- deriving (Show)--isAdjunctionPhase :: GenerationPhase -> Bool-isAdjunctionPhase AdjunctionPhase = True-isAdjunctionPhase _ = False-\end{code}--\subsection{SimpleState and SimpleStatus}--The \fnreflite{SimpleState} is a state monad where the state being-thread through is a \fnreflite{SimpleStatus}.  The two are named-deliberately alike to indicate their close relationship.--To prevent confusion, we ought to keep a somewhat consistent naming-scheme across the builders: FooState for the state monad, FooStatus for-the state monad's ``contents'', and FooItem for the chart items-manipulated.--Note the theTrash is not actually essential to the operation of the-generator; it is for pratical debugging of grammars.  Instead of-trees dissapearing off the face of the debugger; they go into the-trash where the user can inspect them and try to figure out why they-went wrong.--\begin{code}-type SimpleState a = B.BuilderState SimpleStatus a--data SimpleStatus = S-  { theAgenda    :: Agenda-  , theHoldingPen :: AuxAgenda-  , theChart     :: Chart-  , theTrash   :: Trash-  , theResults :: [SimpleItem]-  , theIafMap  :: IafMap -- for index accessibility filtering-  , tsem       :: BitVector-  , step       :: GenerationPhase-  , gencounter :: Integer-  , genconfig  :: Params-  -- we keep a SemBitMap strictly to help display the semantics-  , semBitMap  :: SemBitMap-  }-  deriving Show-\end{code}--\subsubsection{SimpleStatus updaters}--\begin{code}-addToAgenda :: SimpleItem -> SimpleState ()-addToAgenda te =-  modify $ \s -> s{theAgenda = te : theAgenda s }--updateAgenda :: Agenda -> SimpleState ()-updateAgenda a =-  modify $ \s -> s{theAgenda = a}--addToAuxAgenda :: SimpleItem -> SimpleState ()-addToAuxAgenda te = do-  s <- get-  -- each new tree gets a unique id... this makes comparisons faster-  let counter = gencounter s + 1-      te2 = te { siId = counter }-  put s{gencounter = counter,-        theHoldingPen = te2 : theHoldingPen s }--addToChart :: SimpleItem -> SimpleState ()-addToChart te = do-  modify $ \s -> s { theChart = te:theChart s }-  incrCounter chart_size 1--addToTrash :: SimpleItem -> String -> SimpleState ()-addToTrash te err = do-  disableGui <- gets (hasFlagP DisableGuiFlg . genconfig)-  unless disableGui $-    modify $ \s -> s { theTrash = te2 : theTrash s }-  where-    te2 = modifyGuiStuff (\g -> g { siDiagnostic = err:siDiagnostic g }) te--addToResults :: SimpleItem -> SimpleState ()-addToResults te =-  modify $ \s -> s { theResults = te : theResults s }-\end{code}--\subsection{SimpleItem}--\begin{code}-data SimpleItem = SimpleItem- { siId        :: ChartId- --- , siSubstnodes :: [TagSite]- , siAdjnodes   :: [TagSite]- --- , siSemantics :: BitVector- , siPolpaths  :: BitVector- -- for generation sans semantics- -- , siAdjlist :: [(String,Integer)] -- (node name, auxiliary tree id)- -- for index accesibility filtering (one-phase only)- , siAccesible    :: [ String ] -- it's acc/inacc/undetermined- , siInaccessible :: [ String ] -- that's why you want both- --- -- | actually: a set of pre-terminals and their leaves- , siLeaves  :: [(String, B.UninflectedDisjunction)]- , siDerived :: Tree String- , siRoot    :: TagSite- , siFoot    :: Maybe TagSite- --- , siPendingTb :: [ TagSite ] -- only for one-phase- -- how was this item produced?- , siDerivation :: TagDerivation- -- for the debugger only- , siGuiStuff :: SimpleGuiItem- } deriving (Show)--instance Biplate SimpleItem GeniVal where-  biplate (SimpleItem x1 zss zas x2 x3 x4 x5 zls x6 zr zf zp x7 zg) =-    plate SimpleItem            |- x1-            ||+ zss ||+ zas     |- x2 |- x3 |- x4 |- x5-            ||+ zls             |- x6-            |+ zr  |+ zf ||+ zp |- x7-            |+ zg--instance Biplate (String, B.UninflectedDisjunction) GeniVal where-  biplate (s,d) = plate (,) |- s |+ d--instance DescendGeniVal (String, B.UninflectedDisjunction) where-  descendGeniVal m (s,d) = (s, descendGeniVal m d)---- | Things whose only use is within the graphical debugger-data SimpleGuiItem = SimpleGuiItem- { siHighlight :: [String] -- ^ nodes to highlight- , siNodes :: [GNode]    -- ^ actually a set- -- if there are things wrong with this item, what?- , siDiagnostic :: [String]- , siFullSem :: Sem- , siIdname  :: String- } deriving (Show, Data, Typeable)--instance Biplate SimpleGuiItem GeniVal where-  biplate (SimpleGuiItem x1 zns x2 zsem x3) =-     plate SimpleGuiItem |- x1-                         ||+ zns  |- x2-                         ||+ zsem |- x3--emptySimpleGuiItem :: SimpleGuiItem-emptySimpleGuiItem = SimpleGuiItem [] [] [] [] ""--modifyGuiStuff :: (SimpleGuiItem -> SimpleGuiItem) -> SimpleItem -> SimpleItem-modifyGuiStuff fn i = i { siGuiStuff = fn . siGuiStuff $ i }--type ChartId = Integer--instance DescendGeniVal SimpleItem where-  descendGeniVal s i = s `seq` i `seq`-    i { siSubstnodes = descendGeniVal s (siSubstnodes i)-      , siAdjnodes   = descendGeniVal s (siAdjnodes i)-      , siLeaves  = descendGeniVal s (siLeaves i)-      , siRoot    = descendGeniVal s (siRoot i)-      , siFoot    = descendGeniVal s (siFoot i)-      , siPendingTb = descendGeniVal s (siPendingTb i)-      , siGuiStuff = descendGeniVal s (siGuiStuff i)-     }--instance DescendGeniVal SimpleGuiItem where- descendGeniVal s i = i { siNodes = descendGeniVal s (siNodes i) }-\end{code}--\begin{code}-{-# INLINE closedAux #-}---- | True if the chart item has no open substitution nodes-closed :: SimpleItem -> Bool-closed = null.siSubstnodes---- | True if the chart item is an auxiliary tree-aux :: SimpleItem -> Bool-aux = isJust . siFoot---- | True if both 'closed' and 'aux' are True-closedAux :: SimpleItem -> Bool-closedAux x = aux x && closed x--adjdone :: SimpleItem -> Bool-adjdone = null.siAdjnodes--siInitial :: SimpleItem -> Bool-siInitial =  isNothing . siFoot-\end{code}--% ---------------------------------------------------------------------\section{Initialisation}-% ----------------------------------------------------------------------\begin{code}--- | Creates an initial SimpleStatus.-initSimpleBuilder ::  Bool -> B.Input -> Params -> (SimpleStatus, Statistics)-initSimpleBuilder twophase input config =-  let disableGui = hasFlagP DisableGuiFlg config-      cands   = map (initSimpleItem disableGui bmap) $ B.inCands input-      (sem,_,_) = B.inSemInput input-      bmap    = defineSemanticBits sem-      -- FIXME: I don't know if this matters for one-phase-      -- because of on-the-fly tb unification (in 2p), we-      -- need an initial tb step that only addresses the-      -- nodes with null adjunction constraints-      simpleDp = if twophase then simpleDispatch_2p-                 else simpleDispatch_1p (hasOpt Iaf config)-      initialDp = dpTbFailure >--> simpleDp-      ---      initS = S{ theAgenda    = []-               , theHoldingPen = []-               , theChart     = []-               , theTrash     = []-               , theResults   = []-               , semBitMap = bmap-               , tsem      = semToBitVector bmap sem-               , theIafMap = semToIafMap sem-               , step     =  SubstitutionPhase-               , gencounter = toInteger $ length cands-               , genconfig  = config }-      ---  in B.unlessEmptySem input config $-     runState (execStateT (mapM initialDp cands) initS) (B.initStats config)---initSimpleItem :: Bool -- ^ disable gui-               -> SemBitMap -> (TagElem, BitVector) -> SimpleItem-initSimpleItem disableGui bmap (teRaw,pp) =- let (te,tlite) = renameNodesWithTidnum teRaw in- case detectSites (ttree te) of- (snodes,anodes,nullAdjNodes) -> setIaf $ SimpleItem-  { siId        = tidnum te-  , siSemantics = semToBitVector bmap (tsemantics te)-  , siSubstnodes = snodes-  , siAdjnodes   = anodes-  , siPolpaths  = pp-  -- for index accesibility filtering-  , siAccesible    = [] -- see below-  , siInaccessible = []-  -- for generation sans semantics-  -- , siAdjlist = []-  , siLeaves  = map (second (uncurry B.UninflectedDisjunction)) $ tagLeaves te-  , siDerived = tlite-  , siRoot = ncopy.root $ theTree-  , siFoot = if ttype te == Initial then Nothing-             else Just . ncopy.foot $ theTree-  , siDerivation = []-  -- note: see comment in initSimpleBuilder re: tb unification-  , siPendingTb = nullAdjNodes-  ---  , siGuiStuff = if disableGui then emptySimpleGuiItem else initSimpleGuiItem te-  }-  where setIaf i = i { siAccesible = iafNewAcc i }-        theTree = ttree te--initSimpleGuiItem :: TagElem -> SimpleGuiItem-initSimpleGuiItem te = SimpleGuiItem- { siHighlight = []- , siNodes = flatten.ttree $ te- , siDiagnostic = []- , siFullSem = tsemantics te- , siIdname = idname te }--renameNodesWithTidnum :: TagElem -> (TagElem, Tree NodeName)-renameNodesWithTidnum te =-  ( te { ttree = mapTree' renameNode theTree }-  , mapTree' newName theTree )-  where theTree = ttree te-        renameNode n = n { gnname = newName n }-        newName n = gnname n ++ "-" ++ tidstr-        tidstr = show . tidnum $ te-\end{code}--% ---------------------------------------------------------------------\section{Generate}-% ----------------------------------------------------------------------\subsection{One-phase generation}--This is a standard chart-and-agenda mechanism, where each iteration-consists of picking an item off the agenda and combining it with-elements from the chart.--\begin{code}-generateStep_1p :: SimpleState ()-generateStep_1p =- do isDone <- gets (null.theAgenda)-    iaf <- gets (hasOpt Iaf .genconfig)-    let dispatch = mapM (simpleDispatch_1p iaf)-    if isDone-       then return ()-       else do incrCounter num_iterations 1-               given <- selectGiven-               -- do both substitution and adjunction-               applySubstitution1p given >>= dispatch-               passiveAdjunction1p given >>= dispatch-               activeAdjunction1p  given >>= dispatch-               sansAdjunction1p    given >>= dispatch-               -- determine which of the res should go in the agenda-               -- (monadic state) and which should go in the result (res')-               addToChart given-\end{code}--\subsection{Two-phase generation}--Following \cite{carroll1999ecg}, we could also separate realisation into-two distinct phases.  This requires that we maintain two seperate-agendas and process them sequentially, one loop after the other.  See-\fnref{switchToAux} for details.--\begin{itemize}-\item If both Agenda and AuxAgenda are empty then there is nothing to do,-  otherwise, if Agenda is empty then we switch to the application of the-  Adjunction rule.-\item After the rule is applied we classify solutions into those that are complete-  and cover the semantics and those that don't.  The first ones are returned-  and added to the result, while the others are sent back to Agenda.-\item Notice that if we are applying the Substitution rule then the-  current agenda item is added to the chart, otherwise it is deleted.-\end{itemize}--\begin{code}-generateStep_2p :: SimpleState ()-generateStep_2p = do-  nir     <- gets (null.theAgenda)-  curStep <- gets step-  case curStep of-   SubstitutionPhase -> if nir then switchToAux else generateStep_2p_sub-   AdjunctionPhase   -> if nir then return ()   else generateStep_2p_adj--generateStep_2p_sub :: SimpleState ()-generateStep_2p_sub =-  do incrCounter num_iterations 1-     -- choose an item from the agenda-     given <- selectGiven-     res <- applySubstitution given-     mapM_ simpleDispatch_2p res-     -- put the given into the chart untouched-     addToChart given--generateStep_2p_adj :: SimpleState ()-generateStep_2p_adj =-  do incrCounter num_iterations 1-     -- choose an item from the agenda-     given <- selectGiven-     res <- liftM2 (++) (applyAdjunction2p given) (sansAdjunction2p given)-     mapM_ simpleDispatch_2p_adjphase res-     when (adjdone given) $ trashIt given-\end{code}--\subsection{Helpers for the generateSteps}--\begin{code}-trashIt :: SimpleItem -> SimpleState ()-trashIt item =- do disableGui <- gets (hasFlagP DisableGuiFlg . genconfig)-    unless disableGui $ do-    s <- get-    let bmap = semBitMap s-        itemSem = siSemantics item-        inputSem = tsem s-        reason = if inputSem == itemSem-                    then "unknown reason!"-                    else ts_semIncomplete $ bitVectorToSem bmap $ inputSem `xor` itemSem-    addToTrash item reason---- | Arbitrarily selects and removes an element from the agenda and---   returns it.-selectGiven :: SimpleState SimpleItem-selectGiven = do-  agenda <- gets theAgenda-  case agenda of-   [] -> geniBug "null agenda in selectGiven"-   (a:atail) -> updateAgenda atail >> return a-\end{code}--\subsection{Switching phases}--After the substitution and na-constraint phases are complete, we switch to the-final adjunction phase.  We do this by deleting junk from the agenda-(particularly, trees with open substitution sites remaining), transfering trees-from the holding pen to the chart and setting the phase to AdjunctionPhase--\begin{code}-switchToAux :: SimpleState ()-switchToAux = do-  st <- get-  let oldAuxTrees = theHoldingPen st-      config = genconfig st-      -- You might be wondering why we ignore the auxiliary trees in the-      -- chart; this is because all the syntactically complete auxiliary-      -- trees have already been filtered away by calls to classifyNew-      initialT  = filter siInitial (theChart st)-      (compT1, incompT1) = partition (null.siSubstnodes) initialT-      ---      (auxTrees, compT2) =-        if hasOpt EarlyNa config-        then ( mapMaybe (detectNa oldAuxTrees) oldAuxTrees-             , mapMaybe (detectNa auxTrees) compT1 )-        else ( oldAuxTrees, compT1 )-      ---      (compT3, incompT3) =-        if hasOpt SemFiltered config-        then semfilter (tsem st) auxTrees compT2-        else (compT2, [])-      ---      compT = compT3-  -- the root cat filter by Claire-  put st{ theAgenda = []-        , theHoldingPen = []-        , theChart = auxTrees-        , step = AdjunctionPhase }-  mapM_ simpleDispatch_2p_adjphase compT-  -- toss the syntactically incomplete stuff in the trash-  mapM_ (\t -> addToTrash t ts_synIncomplete) incompT1-  mapM_ (\t -> addToTrash t "sem-filtered") incompT3-\end{code}--\subsubsection{SemFilter Optimisation}-\label{sec:semfilter}--The purpose of the semantic filter optimisation is to take full-advantage of Carroll's delayed adjunction.  Consider the semantics-\semexpr{def(m), poor(m), brokenhearted(m), man(m), def(w), woman(w),-beautiful(w), heartless(w), rejects(w,m)}.  At the switchToAux step, we-are left with the initial trees \natlang{man}, \natlang{woman}, \natlang{the-  woman rejects the man}.--It would be nice to filter out the structures \natlang{man} and \natlang{woman}-since we know that they are not going to be semantically complete even with-adjunction.  More precisely, on the switch to adjunction, we do the following:--\begin{itemize}-\item Take the union of the semantics of all auxiliary trees; which-      we call $\phi^*$-\item Delete any initial tree with semantics $\phi^s$ such that-      $\phi^s \cup \phi^*$ is not the target semantics-\end{itemize}--In other words, we delete all initial trees that cannot produce a semantically-complete result even with the help of auxiliary trees.--FIXME: comment 2006-04-18: sem filter each polarity path separately (this is-more aggressive; it gives us much more filtering)--\begin{code}-semfilter :: BitVector -> [SimpleItem] -> [SimpleItem] -> ([SimpleItem], [SimpleItem])-semfilter inputsem auxs initial =-  let auxsem x = foldl' (.|.) 0 [ siSemantics a | a <- auxs, siPolpaths a .&. siPolpaths x /= 0 ]-      -- lite, here, means sans auxiliary semantics-      notjunk x = (siSemantics x) .&. inputsemLite == inputsemLite-                  where inputsemLite = inputsem `xor` (auxsem x)-      -- note that we can't just compare against siSemantics because-      -- that would exclude trees that have stuff in the aux semantics-      -- which would be overzealous-  in partition notjunk initial-\end{code}--% ---------------------------------------------------------------------\section{Operations}-% ----------------------------------------------------------------------We implement the two TAG operations, substitution and adjunction, below.-These are the only two operations we have, because we're working with a-very simple builder that constructs derived trees.--% ---------------------------------------------------------------------\subsection{Substitution}-\label{sec:substitution}-% ----------------------------------------------------------------------\paragraph{applySubstitution} Given a SimpleItem it returns the list of all-possible substitutions between it and the elements in Chart--\begin{code}-applySubstitution :: SimpleItem -> SimpleState ([SimpleItem])-applySubstitution item =- do gr <- lookupChart item-    active  <- mapM (\x -> iapplySubst True item x) gr-    passive <- mapM (\x -> iapplySubst True x item) gr-    let res = concat $ active ++ passive-    incrCounter num_comparisons (2 * (length gr))-    return res--applySubstitution1p :: SimpleItem -> SimpleState ([SimpleItem])-applySubstitution1p item =- do gr <- lookupChart item-    active  <- if adjdone item then return []-               else mapM (\x -> iapplySubst False item x) gr-    passive <- mapM (\x -> iapplySubst False x item) $ filter adjdone gr-    let res = concat $ active ++ passive-    incrCounter num_comparisons (2 * (length gr))-    return res---- | Note: returns ONE possible substitution (the head node)---   of the first in the second.  As all substitutions nodes should---   be substituted we force substitution in order.-iapplySubst :: Bool -> SimpleItem -> SimpleItem -> SimpleState [SimpleItem]-iapplySubst twophase item1 item2 | siInitial item1 && closed item1 = {-# SCC "applySubstitution" #-}- case siSubstnodes item2 of- [] -> return []- ((TagSite n fu fd nOrigin) : stail) ->-  let doIt =-       do -- Maybe monad-          let r@(TagSite rn ru rd rOrigin) = siRoot item1-          (newU, subst1) <- unifyFeat ru fu-          (newD, subst2) <- unifyFeat (replace subst1 rd)-                                      (replace subst1 fd)-          let subst = mergeSubst subst1 subst2-              nr    = TagSite rn newU newD rOrigin-              adj1  = nr : (delete r $ siAdjnodes item1)-              adj2  = siAdjnodes item2-              item1g = item1 { siGuiStuff = g2 }-                where g2 = g { siNodes = repList (gnnameIs rn) newRoot (siNodes g) }-                      g  = siGuiStuff item1-              -- gui stuff-              newRoot g = g { gup = newU, gdown = newD, gtype = Other }-          let pending = if twophase then []-                        else nr : (siPendingTb item1 ++ siPendingTb item2)-          return $! replace subst $ combineSimpleItems [rn] item1g $-                     item2 { siSubstnodes = stail ++ (siSubstnodes item1)-                           , siAdjnodes   = adj2 ++ adj1-                           , siDerived    = plugTree (siDerived item1) n (siDerived item2)-                           , siDerivation = addToDerivation 's' (item1g,rOrigin) (item2,nOrigin,n)-                           , siLeaves     = (siLeaves item1) ++ (siLeaves item2)-                           , siPendingTb  = pending-                           }-  in case doIt of-     Nothing -> return []-     Just x  -> do incrCounter "substitutions" 1-                   return [x]-iapplySubst _ _ _ = return []-\end{code}--% ---------------------------------------------------------------------\subsection{Adjunction}-\label{sec:adjunction}-\label{sec:ordered_adjunction}-\label{sec:foot_constraint}-% -----------------------------------------------------------------\paragraph{applyAdjunction2p} Given a SimpleItem, it returns the list of all-possible adjunctions between it and the elements in Chart.-The Chart contains Auxiliars, while SimpleItem is an Initial--Note: as of 13 april 2005 - only uses ordered adjunction as described in-\cite{kow04a}-\begin{code}-applyAdjunction2p :: SimpleItem -> SimpleState ([SimpleItem])-applyAdjunction2p item = {-# SCC "applyAdjunction2p" #-}- do gr <-lookupChart item-    incrCounter num_comparisons (length gr)-    mapMaybeM (\a -> tryAdj True a item) gr--passiveAdjunction1p :: SimpleItem -> SimpleState [SimpleItem]-passiveAdjunction1p item | closed item && siInitial item =-  do gr <- lookupChart item-     mapMaybeM (\a -> tryAdj False a item) $ filter validAux gr-passiveAdjunction1p _ = return []--activeAdjunction1p :: SimpleItem -> SimpleState [SimpleItem]-activeAdjunction1p item | validAux item =-  do gr <- lookupChart item-     mapMaybeM (\p -> tryAdj False item p) $ filter (\x -> siInitial x && closed x) gr-activeAdjunction1p _ = return []--validAux :: SimpleItem -> Bool-validAux t = closedAux t && adjdone t--tryAdj :: Bool -> SimpleItem -> SimpleItem -> SimpleState (Maybe SimpleItem)-tryAdj twophase aItem pItem =- do case iapplyAdjNode twophase aItem pItem of-     Just x  -> do incrCounter "adjunctions" 1-                   return $ Just x-     Nothing -> return Nothing-\end{code}--Note that in the one-phase variant of non-adjunction, we can't do top/bot-unification on the fly, because afaik we can't tell that a node will never-be revisited.  One example of this is if you try to adjoin into the root--\begin{code}--- | Ignore the next adjunction node-sansAdjunction1p, sansAdjunction2p :: SimpleItem -> SimpleState [SimpleItem]-sansAdjunction1p item | closed item =- case siAdjnodes item of- [] -> return []- (ahead : atail) ->-   return $ [item { siAdjnodes = atail-                  , siPendingTb = ahead : (siPendingTb item) } ]-sansAdjunction1p _ = return []---- | Ignore the next adjunction node-sansAdjunction2p item | closed item =- case siAdjnodes item of- [] -> return []- (TagSite gn t b o: atail) -> do-  -- do top/bottom unification on the node-  case unifyFeat t b of-   Nothing ->-     do addToTrash (modifyGuiStuff (\g -> g { siHighlight = [gn] }) item)-                   ts_tbUnificationFailure-        return []-   Just (tb,s) ->-     let item1 = if isRootOf item gn-                 then item { siRoot = TagSite gn tb [] o }-                 else item-         item2 = modifyGuiStuff (constrainAdj gn tb) item1-     in return $! [replace s $! item2 { siAdjnodes = atail }]-sansAdjunction2p _ = return []-\end{code}--The main work for adjunction is done in the helper function below-(see also figure \ref{fig:adjunction}).-Auxiliary tree \texttt{te1} has a root node \texttt{r} and a foot-node \texttt{f}. Main tree \texttt{te2} has an adjunction site \texttt{an}.-The resulting tree \texttt{res} is a result of splicing \texttt{te1} into-\texttt{te2}.  We replace \texttt{s} with the nodes \texttt{anr} and-\texttt{anf} (which are the results of unifying \texttt{an} with \texttt{r}-             and \texttt{f} respectively).--\begin{figure}-\begin{center}-\includegraphics[scale=0.5]{images/adjunction.pdf}-\label{fig:adjunction}-\caption{iapplyAdjNode}-\end{center}-\end{figure}--In addition to the trees proper, we have to consider that each tree has-a list with a copy of its adjunction sites.  The adjunction list of the-result (\texttt{adjnodes res}) should then contain \texttt{adjnodes te1}-and \texttt{adjnodes te2}, but replacing \texttt{r} and \texttt{an}-with \texttt{anr}.--\begin{code}-iapplyAdjNode :: Bool -> SimpleItem -> SimpleItem -> Maybe SimpleItem-iapplyAdjNode twophase aItem pItem = {-# SCC "iapplyAdjNode" #-}- case siAdjnodes pItem of- [] -> Nothing- (pSite : pTail) -> do-  -- let's go!-  (anr, anf, subst12) <- canAdjoin aItem pSite-  let r = siRoot aItem-  f <- siFoot aItem-  let an_name = tsName pSite-      -- the new adjunction nodes-      auxlite = delete r $ siAdjnodes aItem-      newadjnodes = anr : (pTail ++ auxlite)-      -- Ugh, this is horrible: this is just to make sure the GUI gets-      -- updated accordingly.  The code used to be a lot simpler, but-      -- I started trying to move stuff out of the way in the interests-      -- of efficiency, and to pack as much gui-related stuff as possible-      -- into a single tuple.-      aItem2 = aItem { siGuiStuff = fixNodes $ siGuiStuff aItem }-        where fixNodes g = g { siNodes = map (setSites anr) (siNodes g) }-              setSites (TagSite n u d _) gn =-                if gnname gn == n then gn { gup = u, gdown = d }-                                  else gn-      rawCombined =-        combineSimpleItems [tsName r, an_name] aItem2 $ pItem-               { siAdjnodes = newadjnodes-               , siLeaves  = siLeaves aItem ++ siLeaves pItem-               , siDerived = spliceTree (tsName f) (siDerived aItem) an_name (siDerived pItem)-               , siDerivation = addToDerivation 'a' (aItem,tsOrigin r) (pItem,tsOrigin pSite,an_name)-               -- , siAdjlist = (n, (tidnum te1)):(siAdjlist item2)-               -- if we adjoin into the root, the new root is that of the aux-               -- tree (affects 1p only)-               , siRoot = if isRootOf pItem an_name then r else siRoot pItem-               , siPendingTb =-                  if twophase then []-                  else anf : (siPendingTb pItem) ++ (siPendingTb aItem)-               }-      -- one phase = postpone tb unification-      -- two phase = do tb unification on the fly-      finalRes1p = return $ replace subst12 rawCombined-      finalRes2p =-       do -- tb on the former foot-          tbRes <- unifyFeat (tsUp anf) (tsDown anf)-          let (anf_tb, subst3) = tbRes-              myRes = modifyGuiStuff (constrainAdj an_name anf_tb) res'-          -- apply the substitutions-              res' = replace (mergeSubst subst12 subst3) rawCombined-          return myRes-  -- ----------------  if twophase then finalRes2p else finalRes1p---- Note that we do not propagate variable substitutions in the nodes we return-canAdjoin :: SimpleItem -> TagSite -> Maybe (TagSite, TagSite, Subst)-canAdjoin aItem pSite = do-  -- let's go!-  let r = siRoot aItem -- auxiliary tree, eh?-  f <- siFoot aItem -- should really be an error if fails-  (anr_up',  subst1)  <- unifyFeat (tsUp r) (tsUp pSite)-  (anf_down, subst2)  <- unifyFeat (replace subst1 $ tsDown f) (replace subst1 $ tsDown pSite)-  let -- combined substitution list and success condition-      subst12 = mergeSubst subst1 subst2-      anr = replace subst12 $ r { tsUp = anr_up' }-      anf = replace subst12 $ pSite { tsDown = anf_down }-  return (anr, anf, subst12)-\end{code}--\begin{code}-detectNa :: [SimpleItem] -- ^ aux trees-         -> SimpleItem   -- ^ me-         -> Maybe SimpleItem-detectNa rawAux i = helper (siAdjnodes i) Map.empty []- where-  compatAux = filterCompatible i rawAux-  helper []     s acc = Just $ replace s $ i { siAdjnodes = acc }-  helper (t:ts) s acc =-    let hasAdj = any isJust $ map (\a -> canAdjoin a t) compatAux-    in case (snd `fmap` unifyFeat (tsUp t) (tsDown t)) of-        Just s2 -> if hasAdj-                   then helper ts s (t : acc)-                   else helper (replace s2 ts) (mergeSubst s s2) acc-        Nothing -> if hasAdj-                   then helper ts s (t : acc)-                   else Nothing-\end{code}--% ---------------------------------------------------------------------\subsection{Helper functions for operations}-% ----------------------------------------------------------------------\begin{code}-ncopy :: GNode -> TagSite-ncopy x = TagSite (gnname x) (gup x) (gdown x) (gorigin x)--isRootOf :: SimpleItem -> String -> Bool-isRootOf item n = n == rname-  where (TagSite rname _ _ _) = siRoot item---- | Retrieves a list of trees from the chart which could be combined with the given agenda tree.--- The current implementation searches for trees which---  * do not have overlapping semantics with the given---  * are on the some of the same polarity automaton paths as the---    current agenda item-lookupChart :: SimpleItem -> SimpleState [SimpleItem]-lookupChart given = gets (filterCompatible given . theChart)--filterCompatible :: SimpleItem -> [SimpleItem] -> [SimpleItem]-filterCompatible given chart =-  [ i | i <- chart-      -- should be on the same polarity path (chart sharing)-      , (siPolpaths i) .&. gpaths /= 0-      -- semantics should not be overlapping-      && (siSemantics i .&. gsem ) == 0-  ]- where-  gpaths = siPolpaths given-  gsem   = siSemantics given---- | Helper function for when chart operations succeed.-combineSimpleItems :: [NodeName] -- ^ nodes to highlight-                   -> SimpleItem -> SimpleItem -> SimpleItem-combineSimpleItems hi item1 item2 = {-# SCC "combineSimpleItems" #-}-  item2 { siSemantics = siSemantics item1 .|. siSemantics item2-        , siPolpaths  = siPolpaths  item1 .&. siPolpaths  item2-        , siGuiStuff  = combineSimpleGuiItems hi (siGuiStuff item1) (siGuiStuff item2)-        }--combineSimpleGuiItems :: [NodeName]-                      -> SimpleGuiItem -> SimpleGuiItem -> SimpleGuiItem-combineSimpleGuiItems hi item1 item2 =- item2 { siFullSem = sortSem $ siFullSem item1 ++ siFullSem item2-       , siNodes = siNodes item1 ++ siNodes item2-       , siDiagnostic = siDiagnostic item1 ++ siDiagnostic item2-       , siHighlight = hi-       }--constrainAdj :: String -> Flist -> SimpleGuiItem -> SimpleGuiItem-constrainAdj gn newT g =-  g { siNodes = repList (gnnameIs gn) fixIt (siNodes g) }-  where fixIt n = n { gup = newT, gdown = [], gaconstr = True }-\end{code}--\subsubsection{Derivation trees}--We make the simplifying assumption that each chart item is only used once.-This is clearly wrong if we allow for items with an empty semantics, but-since we do not actually allow such a thing, we're ok.--\begin{code}-addToDerivation :: Char-                -> (SimpleItem,String)-                -> (SimpleItem,String,String)-                -> TagDerivation-addToDerivation op (tc,tcOrigin) (tp,tpOrigin,tpSite) =-  let hp = siDerivation tp-      hc = siDerivation tc-      newnode = DerivationStep op tcOrigin tpOrigin tpSite-  in newnode:hp++hc-\end{code}----% ---------------------------------------------------------------------\section{Dispatching new results}-% ----------------------------------------------------------------------Dispatching is the process where new chart items are assigned to one of-the trash, agenda, auxiliary agenda or chart.  The item could be-modified during dispatch-time; for example, we might do top/bottom-unification on it.  See \ref{sec:dispatching} for more details.--\begin{code}-type SimpleDispatchFilter = DispatchFilter SimpleState SimpleItem--simpleDispatch_2p :: SimpleDispatchFilter-simpleDispatch_2p =- simpleDispatch (dpRootFeatFailure >--> dpToResults)-                (dpAux >--> dpToAgenda)--simpleDispatch_2p_adjphase :: SimpleDispatchFilter-simpleDispatch_2p_adjphase =- simpleDispatch (dpRootFeatFailure >--> dpToResults)-                dpToAgenda--simpleDispatch_1p :: Bool -> SimpleDispatchFilter-simpleDispatch_1p iaf =- simpleDispatch (dpRootFeatFailure >--> dpTbFailure >--> dpToResults)-                (maybeDpIaf >--> dpToAgenda)- where maybeDpIaf = if iaf then dpIafFailure else nullFilter--simpleDispatch :: SimpleDispatchFilter -> SimpleDispatchFilter -> SimpleDispatchFilter-simpleDispatch resFilter nonResFilter item =- do inputsem <- gets tsem-    let synComplete x = siInitial x && closed x && adjdone x-        semComplete x = inputsem == siSemantics x-        isResult x = synComplete x && semComplete x-    condFilter isResult resFilter nonResFilter item--dpAux, dpToAgenda :: SimpleDispatchFilter-dpTbFailure, dpToResults :: SimpleDispatchFilter-dpToTrash :: String -> SimpleDispatchFilter--dpToAgenda x  = addToAgenda x  >> return Nothing-dpToResults x = addToResults x >> return Nothing-dpToTrash m x = addToTrash x m >> return Nothing--dpAux item =-  if closedAux item-  then addToAuxAgenda item >> return Nothing-  else return $ Just item--{---- | Dispatches to the trash and returns Nothing if there is a tree---   size limit in effect and the item is over that limit.  The---   tree size limit is used in 'IgnoreSemantics' mode.-dpTreeLimit item =- do config <- gets genconfig-    case maxTrees config of-     Nothing  -> return $ Just item-     Just lim -> if (length.snd.siDerivation) item > lim-                 then do addToTrash item (ts_overnumTrees lim)-                         return Nothing-                 else return $ Just item-   where ts_overnumTrees l = "Over derivation size of " ++ (show l)--}---- | This is only used for the one-phase algorithm-dpTbFailure item =- return $ if tbUnifyTree item then Just item else Nothing---- | If the item (ostensibly a result) does not have the correct root---   category, return Nothing; otherwise return Just item-dpRootFeatFailure :: SimpleDispatchFilter-dpRootFeatFailure item =- do config <- gets genconfig-    let rootFeat = getListFlagP RootFeatureFlg config-        (TagSite _ top _ _) = siRoot item-    case unifyFeat rootFeat top of-      Nothing ->-        dpToTrash (ts_rootFeatureMismatch rootFeat) item-      Just (_, s) ->-        return . Just $ replace s item-\end{code}-% ---------------------------------------------------------------------\subsection{Top and bottom unification}-% ----------------------------------------------------------------------\paragraph{tbUnifyTree} unifies the top and bottom feature structures-of each node on each tree.  Note: this only determines if it is-possible to do so.  Actually returning the results is possible-and even easy-(you'll have to look back into the darcs repository and unpull the- patch from 2006-05-21T15:40:51 ``Remove top/bot unification standalone- code.'')-but since it is only used in the one-phase algorithm and for the-graphical interface, I decided not to bother.--\begin{code}-type TbEither = Either String Subst-tbUnifyTree :: SimpleItem -> Bool-tbUnifyTree item = {-# SCC "tbUnifyTree" #-}-  case foldl' tbUnifyNode (Right Map.empty) (siPendingTb item) of-    Left  _ -> False-    Right _ -> True-\end{code}--Our helper function corresponds to the first unification step.  It is-meant to be called from a fold.  The node argument represents the-current node being explored.  The Either argument holds a list of-pending substitutions and a copy of the entire tree.--There are two things going on in here:--\begin{enumerate}-\item check if unification is possible - first we apply the pending-      substitutions on the node and then we check if unification-      of the top and bottom feature structures of that node-      succeeds-\item keep track of the substitutions that need to be performed --      any new substitutions that result from unification are-      added to the pending list-\end{enumerate}--Note that we wrap the second argument in a Maybe; this is used to-indicate that if unification suceeds or fails.  We also use it to-prevent the function from doing any work if a unification failure-from a previous call has already occured.--Getting this right was a big pain in the butt, so don't go trying to-simplify this over-complicated code unless you know what you're doing.--\begin{code}-tbUnifyNode :: TbEither -> TagSite -> TbEither-tbUnifyNode (Right pending) rawSite =-  -- apply pending substitutions-  case replace pending rawSite of-  (TagSite name up down _) ->-    -- check top/bottom unification on this node-    case unifyFeat up down of-    -- stop all future iterations-    Nothing -> Left name-    -- apply any new substutions to the whole tree-    Just (_,sb) -> Right (mergeSubst pending sb)---- if earlier we had a failure, don't even bother-tbUnifyNode (Left n) _ = Left n-\end{code}--% ---------------------------------------------------------------------\subsection{Index accesibility filtering}-\label{sec:simple:iaf}-% ----------------------------------------------------------------------Note that index accesibility filtering only makes sense for the one-phase-algorithm.  See also \ref{sec:iaf} for more details about what this is.--\begin{code}-instance IafAble SimpleItem where-  iafAcc   = siAccesible-  iafInacc = siInaccessible-  iafSetAcc   a i = i { siAccesible = a }-  iafSetInacc a i = i { siInaccessible = a }-  iafNewAcc i =-    concatMap fromUniConst $-    concat [ getIdx up | (TagSite _ up _ _) <- siSubstnodes i ]--dpIafFailure :: SimpleDispatchFilter-dpIafFailure item | aux item = return $ Just item-dpIafFailure itemRaw =- do s <- get-    let bmap = semBitMap s-        item = recalculateAccesibility itemRaw-        badSem = iafBadSem (theIafMap s) bmap (tsem s) siSemantics item-        inAcc = iafInacc item-    if badSem == 0-      then -- can't dispatch, but that's good!-           -- (note that we return the item with its iaf criteria updated)-           return $ Just item-      else dpToTrash (ts_iafFailure inAcc $ bitVectorToSem bmap badSem) item-\end{code}---% ---------------------------------------------------------------------\section{Unpacking the results}-% ----------------------------------------------------------------------Unpacking the results consists of converting each result into a sentence-automaton (to take care of atomic disjunction) and reading the paths of-each automaton.--\begin{code}-unpackResults :: [SimpleItem] ->  [B.Output]-unpackResults = concatMap unpackResult--unpackResult :: SimpleItem -> [B.Output]-unpackResult item =-  let leafMap :: Map.Map String B.UninflectedDisjunction-      leafMap = Map.fromList . siLeaves $ item-      lookupOrBug :: NodeName -> B.UninflectedDisjunction-      lookupOrBug k = case Map.lookup k leafMap of-                      Nothing -> geniBug $ "unpackResult : could not find node " ++ k-                      Just w  -> w-      derivation = siDerivation item-      paths = automatonPaths . listToSentenceAut $-              [ lookupOrBug k | (k,_) <- (preTerminals . siDerived) item ]- in zip paths (repeat derivation)-\end{code}--\subsection{Sentence automata}--\fnlabel{listToSentenceAut} converts a list of GNodes into a sentence-automaton.  It's a actually pretty stupid conversion in fact.  We pretty-much make a straight path through the automaton, with the only-cleverness being that we provide a different transition for each-atomic disjunction.--\begin{code}-listToSentenceAut :: [ B.UninflectedDisjunction ] -> B.SentenceAut-listToSentenceAut nodes =-  let theStart  = 0-      theEnd = length nodes - 1-      theStates = [theStart..theEnd]-      ---      emptyAut = NFA-        { startSt     = theStart-        , isFinalSt   = Nothing-        , finalStList = [theEnd]-        , states      = [theStates]-        , transitions = Map.empty }-      -- create a transition for each lexeme in the node to the-      -- next state...-      helper :: (Int, B.UninflectedDisjunction) -> B.SentenceAut -> B.SentenceAut-      helper (current, B.UninflectedDisjunction lemmas features) aut =-        foldl' addT aut lemmas-        where-          addT a t = addTrans a current (Just (LemmaPlus t features)) next-          next = current + 1-      ---  in foldr helper emptyAut (zip theStates nodes)-\end{code}--% ---------------------------------------------------------------------\section{Partial results}-% ----------------------------------------------------------------------The user may ask for partial results when realisation fails.  We implement this-using a greedy, full-commitment algorithm.  Find the discarded result that-matches the largest part of the semantics and output that fragment.  If there-are parts of the input semantics not covered by that fragment, search for the-largest chunk that covers the missing semantics.  Recurse until there are no-more eligible items.--\begin{code}-partialResults :: SimpleStatus -> [SimpleItem]-partialResults st = unfoldr getNext 0- where-  inputsem = tsem st-  trash  = theTrash st-  trashC = sortBy (comparing $ negate . fst) $-           map (\t -> (coverage inputsem t, t)) trash-  getNext sem = case getItems sem of-                     []     -> Nothing-                     (it:_) -> Just (it, siSemantics it .|. sem)-  getItems sem = [ i | (_,i) <- trashC, siSemantics i .&. sem == 0 ]--coverage :: BitVector -> SimpleItem -> Int-coverage sem it = countBits (sem .&. siSemantics it)--countBits :: Bits a => a -> Int-countBits 0  = 0-countBits bs = if testBit bs 0 then 1 + next else next-  where next = countBits (shiftR bs 1)-\end{code}--% ---------------------------------------------------------------------% Performance-% ----------------------------------------------------------------------\begin{code}-{--instance NFData SimpleItem where-  rnf (SimpleItem x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 x13-      ) = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` rnf x4 `seq` rnf x5 `seq` rnf x6-                 `seq` rnf x7 `seq` rnf x8 `seq` rnf x9 `seq` rnf x10 `seq` rnf x11-                 `seq` rnf x11 `seq` rnf x12 `seq` rnf x13-                 `seq` rnf x14--}-\end{code}-
− src/NLP/GenI/Simple/SimpleGui.lhs
@@ -1,208 +0,0 @@-% GenI surface realiser-% Copyright (C) 2005 Carlos Areces and Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.--\chapter{Simple GUI}--\begin{code}-{-# OPTIONS_GHC -fno-warn-orphans #-}-module NLP.GenI.Simple.SimpleGui where-\end{code}--\ignore{-\begin{code}-import Graphics.UI.WX--import Control.Arrow ( (&&&) )-import Data.IORef-import qualified Data.Map as Map--import NLP.GenI.Statistics (Statistics)--import NLP.GenI.Btypes (GNode(gnname, gup), AvPair(..), emptyGNode, GeniVal(GConst))-import NLP.GenI.Configuration ( Params(..) )-import NLP.GenI.Geni ( ProgStateRef, runGeni, GeniResult )-import NLP.GenI.Graphviz ( GraphvizShow(..), gvNewline, gvUnlines )-import NLP.GenI.GuiHelper-  ( messageGui, tagViewerGui,-    debuggerPanel, DebuggerItemBar, setGvParams, GvIO, newGvRef, GraphvizGuiSt(..),-    viewTagWidgets, XMGDerivation(getSourceTrees),-  )-import NLP.GenI.Tags (tsemantics, DerivationStep(dsChild), TagElem(idname, ttree), TagItem(..), emptyTE)-import NLP.GenI.GraphvizShow ( graphvizShowDerivation )--import qualified NLP.GenI.Builder    as B-import NLP.GenI.Builder (LemmaPlus(..))-import qualified NLP.GenI.BuilderGui as BG-import NLP.GenI.Polarity-import NLP.GenI.Simple.SimpleBuilder-  ( simpleBuilder, SimpleStatus, SimpleItem(..), SimpleGuiItem(..)-  , unpackResult-  , step, theResults, theAgenda, theHoldingPen, theChart, theTrash)-\end{code}-}--% ---------------------------------------------------------------------\section{Interface}-% ----------------------------------------------------------------------\begin{code}-simpleGui_2p, simpleGui_1p :: BG.BuilderGui-simpleGui_2p = simpleGui True-simpleGui_1p = simpleGui False--simpleGui :: Bool -> BG.BuilderGui-simpleGui twophase = BG.BuilderGui {-      BG.resultsPnl  = resultsPnl twophase-    , BG.debuggerPnl = simpleDebuggerTab twophase }--resultsPnl :: Bool -> ProgStateRef -> Window a -> IO ([GeniResult], Statistics, Layout)-resultsPnl twophase pstRef f =-  do (sentences, stats, st) <- runGeni pstRef (simpleBuilder twophase)-     (lay, _, _) <- realisationsGui pstRef f (theResults st)-     return (sentences, stats, lay)-\end{code}--% ---------------------------------------------------------------------\section{Results}-\label{sec:results_gui}-% ----------------------------------------------------------------------\subsection{Derived Trees}--Browser for derived/derivation trees, except if there are no results, we show a-message box--\begin{code}-realisationsGui :: ProgStateRef -> (Window a) -> [SimpleItem]-                -> GvIO () Bool (Maybe SimpleItem)-realisationsGui _   f [] =-  do m <- messageGui f "No results found"-     g <- newGvRef () False ""-     return (m, g, return ())-realisationsGui pstRef f resultsRaw =-  do let tip = "result"-         itNlabl = map (Just &&& siToSentence) resultsRaw-     ---     pst     <- readIORef pstRef-     -- FIXME: have to show the semantics again-     tagViewerGui pst f tip "derived" itNlabl-\end{code}--% ---------------------------------------------------------------------\section{Debugger}-\label{sec:simple_debugger_gui}-\label{fn:simpleDebugGui}-% ----------------------------------------------------------------------\begin{code}-simpleDebuggerTab :: Bool -> (Window a) -> Params -> B.Input -> String -> IO Layout-simpleDebuggerTab twophase x1 (pa@x2) =-  debuggerPanel (simpleBuilder twophase) False stToGraphviz (simpleItemBar pa)-   x1 x2- -stToGraphviz :: SimpleStatus -> [(Maybe SimpleItem, String)]-stToGraphviz st = -  let agenda    = section "AGENDA"    $ theAgenda    st-      auxAgenda = section "HOLDING"   $ theHoldingPen st-      trash     = section "TRASH"     $ theTrash     st-      chart     = section "CHART"     $ theChart     st-      results   = section "RESULTS"   $ theResults   st-      ---      section n i = hd : (map tlFn i)-        where hd = (Nothing, "___" ++ n ++ "___")-              tlFn x = (Just x, siToSentence x ++ (showPaths $ siPolpaths x))-      showPaths t = " (" ++ showPolPaths t ++ ")"-  in concat [ agenda, auxAgenda, chart, trash, results ]--simpleItemBar :: Params -> DebuggerItemBar SimpleStatus Bool SimpleItem-simpleItemBar pa f gvRef updaterFn =- do ib <- panel f []-    phaseTxt   <- staticText ib [ text := "" ]-    detailsChk <- checkBox ib [ text := "Show features"-                              , checked := False ]-    viewTagLay <- viewTagWidgets ib gvRef pa-    -- handlers-    let onDetailsChk = -         do isDetailed <- get detailsChk checked -            setGvParams gvRef isDetailed-            updaterFn-    set detailsChk [ on command := onDetailsChk ]-    ---    let lay = hfloatCentre . container ib . row 5 $-               [ hspace 5-               , widget phaseTxt-               , hglue-               , widget detailsChk-               , hglue-               , viewTagLay-               , hspace 5 ]-    let onUpdate =-          do status <- gvcore `fmap` readIORef gvRef-             set phaseTxt [ text := show (step status) ]-    return (lay, onUpdate)-\end{code}--% ---------------------------------------------------------------------\section{Miscellaneous}-% ---------------------------------------------------------------------\begin{code}-instance TagItem SimpleItem where- tgIdName    = siIdname.siGuiStuff- tgIdNum     = siId- tgSemantics = siFullSem.siGuiStuff--instance XMGDerivation SimpleItem where- -- Note: this is XMG-related stuff- getSourceTrees it = tgIdName it : (map dsChild . siDerivation $ it)-\end{code}--\begin{code}-instance GraphvizShow Bool SimpleItem where-  graphvizLabel  f c =-    graphvizLabel f (toTagElem c) ++ gvNewline ++ (gvUnlines $ siDiagnostic $ siGuiStuff c)--  graphvizParams f c = graphvizParams f (toTagElem c)-  graphvizShowAsSubgraph f p it =-   let isHiglight n = gnname n `elem` (siHighlight.siGuiStuff) it-       info n | isHiglight n = (n, Just "red")-              | otherwise    = (n, Nothing)-   in    "\n// ------------------- elementary tree --------------------------\n"-      ++ graphvizShowAsSubgraph (f, info) (p ++ "TagElem") (toTagElem it)-      ++ "\n// ------------------- derivation tree --------------------------\n"-      -- derivation tree is displayed without any decoration-      ++ (graphvizShowDerivation . siDerivation $ it)--toTagElem :: SimpleItem -> TagElem-toTagElem si =-  emptyTE { idname = tgIdName si-          , tsemantics = tgSemantics si-          , ttree = fmap lookupOrBug (siDerived si) }-  where-   nodes   = siNodes.siGuiStuff $ si-   nodeMap = Map.fromList $ zip (map gnname nodes) nodes-   lookupOrBug k = case Map.lookup k nodeMap of-                   Nothing -> emptyGNode { gup = [ AvPair "cat" (GConst ["error looking up " ++ k]) ] }-                   Just x  -> x-\end{code}--\begin{code}-siToSentence :: SimpleItem -> String-siToSentence si = case unpackResult si of-                  []    -> siIdname.siGuiStuff $ si-                  (h:_) -> unwords . map lpLemma . fst $ h-\end{code}
src/NLP/GenI/Statistics.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE FlexibleContexts #-} ---------------------------------------------------- --                                                -- -- Statistics.hs:                                 --@@ -29,7 +28,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. -}-+{-# LANGUAGE FlexibleContexts, RankNTypes #-} module NLP.GenI.Statistics(Statistics, StatisticsState,     emptyStats, @@ -46,6 +45,8 @@ import Data.Maybe (mapMaybe) import Text.JSON +import Control.DeepSeq+ ------------------------------------------- -- Statistics are collections of Metrics -- which can be printed out (at regular intervals)@@ -103,3 +104,20 @@ -- not quite showJSON here metricToJSON :: Metric -> (String, JSValue) metricToJSON (IntMetric s i) = (s, showJSON i)++{-!+deriving instance NFData Statistics+deriving instance NFData Metric+!-}+++-- GENERATED START++ +instance NFData Statistics where+        rnf (Stat x1) = rnf x1 `seq` ()++ +instance NFData Metric where+        rnf (IntMetric x1 x2) = rnf x1 `seq` rnf x2 `seq` ()+-- GENERATED STOP
− src/NLP/GenI/SysGeni.hs
@@ -1,77 +0,0 @@--- GenI surface realiser--- Copyright (C) 2005 Carlos Areces and Eric Kow------ This program is free software; you can redistribute it and/or--- modify it under the terms of the GNU General Public License--- as published by the Free Software Foundation; either version 2--- of the License, or (at your option) any later version.------ This program is distributed in the hope that it will be useful,--- but WITHOUT ANY WARRANTY; without even the implied warranty of--- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the--- GNU General Public License for more details.------ You should have received a copy of the GNU General Public License--- along with this program; if not, write to the Free Software--- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.--{-# LANGUAGE ForeignFunctionInterface #-}---- | The SysGeni module mainly exists for running GenI as an application bundle---   under MacOS X.  We mostly re-export stuff from System.Process, but if we---   are in a MacOS X application bundle, then we add @../Resources/bin@---   to the path for the miscellaneous resources that we ship with with GenI.-module NLP.GenI.SysGeni-where--import qualified System.Process as S--import Data.List (isSuffixOf)-import System.FilePath-import System.IO (Handle)-import System.Exit (ExitCode)--#ifdef __GLASGOW_HASKELL__-import Foreign-import Foreign.C-import Control.Monad-#include "ghcconfig.h"-#endif---- * Running a process--waitForProcess :: S.ProcessHandle -> IO ExitCode-waitForProcess = S.waitForProcess---- | One thing special we need to do for Macs is to detect if we're---   running from an application bundle.  If we are, we assume that any---   processes we want to run are in @../Resources/bin@.-runInteractiveProcess :: String -> [String]-                      -> Maybe FilePath-                      -> Maybe [(String, String)]-                      -> IO (Handle, Handle, Handle, S.ProcessHandle)-runInteractiveProcess cmd args x y = do-  dirname <- getProgDirName-  -- detect if we're in an .app bundle, i.e. if -  -- we are running from something.app/Contents/MacOS-  let appBundle = ".app/Contents/MacOS/"-      resBinCmd = "../Resources/bin" </> cmd-  -- if we're in an .app bundle, we should prefix the-  -- path with ../Resources/bin-  let cmd2 = if appBundle `isSuffixOf` dirname -             then resBinCmd else cmd-  S.runInteractiveProcess cmd2 args x y ---- * Process helpers--foreign import ccall unsafe "getProgArgv"-  getProgArgv :: Ptr CInt -> Ptr (Ptr CString) -> IO ()--getProgDirName :: IO String-getProgDirName = -  alloca $ \ p_argc ->-  alloca $ \ p_argv -> do-     getProgArgv p_argc p_argv-     argv <- peek p_argv-     s <- peekElemOff argv 0 >>= peekCString-     return $ takeDirectory s
+ src/NLP/GenI/Tag.hs view
@@ -0,0 +1,396 @@+-- GenI surface realiser+-- Copyright (C) 2005 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.++-- | This module provides basic datatypes specific to Tree Adjoining Grammar+-- (TAG) elementary trees and some low-level operations.++{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE OverloadedStrings #-}++module NLP.GenI.Tag (+   -- Main Datatypes+   Tags, TagElem(..), TagItem(..), TagSite(..),+   TagDerivation, DerivationStep(..), dsChild, dsParent, dsParentSite,+   ts_synIncomplete, ts_semIncomplete, ts_tbUnificationFailure,+   ts_rootFeatureMismatch,++   -- Functions from Tags+   addToTags, tagLeaves, getLexeme, toTagSite,++   -- Functions from TagElem+   setTidnums, plugTree, spliceTree,++   -- General functions+   mapBySem,+   collect, detectSites,+) where++import Control.Applicative ( (<$>), (<*>) )+import qualified Data.Map as Map+import Data.Maybe (fromMaybe, listToMaybe, mapMaybe, catMaybes)+import Data.Tree+import Data.Text ( Text )+import qualified Data.Text as T++import Control.DeepSeq+import Data.Generics (Data)+import Data.Typeable (Typeable)+import Data.FullList hiding ( (++) )+import Text.JSON++import NLP.GenI.FeatureStructure ( AvPair(..), Flist )+import NLP.GenI.General (listRepNode, groupByFM, preTerminals, geniBug)+import NLP.GenI.GeniShow+import NLP.GenI.GeniVal ( GeniVal(..), DescendGeniVal(..), Collectable(..), Idable(..),+                          isConst,+                        )+import NLP.GenI.Polarity.Types ( PolarityKey(..), SemPols )+import NLP.GenI.Pretty+import NLP.GenI.Semantics ( Sem, Literal(..), emptyLiteral )+import NLP.GenI.TreeSchema+    ( Ptype(..), GNode(..), GType(..), NodeName, lexemeAttributes )++-- ----------------------------------------------------------------------+-- Tags+-- ----------------------------------------------------------------------++-- | An anchored grammar.+--   The grammar associates a set of semantic predicates to a list of trees each.+type Tags = Map.Map String [TagElem]                            ++-- | 'addTags' @tags key elem@ adds @elem@ to the the list of elements associated+--   to the key+addToTags :: Tags -> String -> TagElem -> Tags+addToTags t k e = Map.insertWith (++) k [e] t++-- ----------------------------------------------------------------------+-- TagElem+-- ----------------------------------------------------------------------++data TagSite = TagSite+    { tsName :: Text+    , tsUp   :: Flist GeniVal+    , tsDown :: Flist GeniVal+    , tsOrigin :: Text+    }+  deriving (Eq, Ord, Data, Typeable)++data TagElem = TE+    { idname       :: Text+    , ttreename    :: Text+    , tidnum       :: Integer+    , ttype        :: Ptype+    , ttree        :: Tree (GNode GeniVal)+    , tsemantics   :: Sem+     -- optimisation stuff+     -- (polarity key to charge interval)+    , tpolarities  :: Map.Map PolarityKey (Int,Int)+    , tinterface   :: Flist GeniVal  -- for idxconstraints (pol)+    , ttrace       :: [Text]+    , tsempols     :: [SemPols] -- ^ can be empty+    }+  deriving (Eq, Data, Typeable)++-- | Given a tree(GNode) returns a list of substitution or adjunction+--   nodes, as well as remaining nodes with a null adjunction constraint.+detectSites :: Tree (GNode GeniVal) -> ([NodeName], [NodeName], [NodeName])+detectSites t =+  ( sites isSub           -- for substitution+  , sites (not.gaconstr)  -- for adjunction+  , sites constrButNotSub -- for neither+  )+ where+ ns = flatten t+ sites match = map gnname . filter match $ ns+ isSub n = gtype n == Subs+ constrButNotSub n = gaconstr n && (not $ isSub n)++toTagSite :: GNode GeniVal -> TagSite+toTagSite n = TagSite (gnname n) (gup n) (gdown n) (gorigin n)++type TagDerivation = [ DerivationStep ]++data DerivationStep = SubstitutionStep Text Text Text+                    | AdjunctionStep   Text Text Text+                    | InitStep         Text+ deriving (Show, Ord, Eq)++dsOp :: DerivationStep -> Char+dsOp (SubstitutionStep {}) = 's'+dsOp (AdjunctionStep {})   = 'a'+dsOp (InitStep {})         = 'i'++dsChild :: DerivationStep -> Text+dsChild (SubstitutionStep c _ _) = c+dsChild (AdjunctionStep c _ _ )  = c+dsChild (InitStep c)             = c++dsParent :: DerivationStep -> Maybe Text+dsParent (SubstitutionStep _ p _) = Just p+dsParent (AdjunctionStep _ p _)   = Just p+dsParent (InitStep _)             = Nothing++dsParentSite :: DerivationStep -> Maybe Text+dsParentSite (SubstitutionStep _ _ s) = Just s+dsParentSite (AdjunctionStep _ _ s)   = Just s+dsParentSite (InitStep _)             = Nothing++instance JSON DerivationStep where+ readJSON j = do+   jo <- fromJSObject `fmap` readJSON j+   let field x = maybe (fail $ "Could not find: " ++ x) readJSON+               $ lookup x jo+   op    <- field "op"+   child <- field "child"+   case op of+    "s" -> AdjunctionStep   child <$> field "parent" <*> field "parent-node"+    "a" -> SubstitutionStep child <$> field "parent" <*> field "parent-node"+    "i" -> return (InitStep child)+    x   -> fail $ "Don't know about derivation operation '" ++ x ++ "'"+ showJSON x =+     JSObject . toJSObject $ [ ("op",     showJSON $ dsOp x)+                             , ("child",  showJSON $ dsChild x)+                             ] ++ catMaybes+                             [ (\v -> ("parent", showJSON v))      <$> dsParent x+                             , (\v -> ("parent-node", showJSON v)) <$> dsParentSite x+                             ]++instance Ord TagElem where+  compare t1 t2 = +    case (ttype t1, ttype t2) of+         (Initial, Initial)   -> compareId +         (Initial, Auxiliar)  -> LT+         (Auxiliar, Initial)  -> GT+         (Auxiliar, Auxiliar) -> compareId +    where compareId  = compare (tidnum t1) (tidnum t2)++instance DescendGeniVal TagElem where+  descendGeniVal s te =+    te { tinterface = descendGeniVal s (tinterface te)+       , ttree      = descendGeniVal s (ttree te)+       , tsemantics = descendGeniVal s (tsemantics te) }++instance DescendGeniVal TagSite where+  descendGeniVal s (TagSite n fu fd o) = TagSite n (descendGeniVal s fu) (descendGeniVal s fd) o++instance Collectable TagElem where+  collect t = (collect $ tinterface t) . (collect $ ttree t) +            . (collect $ tsemantics t)++instance Idable TagElem where+  idOf = tidnum++-- Substitution and Adjunction++-- | Plug the first tree into the second tree at the specified node.+--   Anything below the second node is silently discarded.+--   We assume the trees are pluggable; it is treated as a bug if+--   they are not!+plugTree :: Tree NodeName+         -> NodeName+         -> Tree NodeName+         -> Tree NodeName+plugTree male n female =+    case listRepNode (const male) (nmatch n) [female] of+         ([r], True) -> r+         _           -> geniBug oops+  where+    oops = "plugTree: unexpected plug failure at node " ++ T.unpack n++-- | Given two trees 'auxt' and 't', splice the tree 'auxt' into+--   't' via the TAG adjunction rule.+spliceTree :: NodeName      -- ^ foot node of the aux tree+           -> Tree NodeName -- ^ aux tree+           -> NodeName      -- ^ place to adjoin in target tree+           -> Tree NodeName -- ^ target tree+           -> Tree NodeName+spliceTree f auxT n top =+    plugTree middle n top +  where+    bottom = fromMaybe (geniBug oops) (findSubTree n top)+    middle = plugTree bottom f auxT+    oops = unwords+        [ "NLP.GenI.Tag.spliceTree:"+        , "Unexpected adjunction failure."+        , "Could not find node " ++ T.unpack n ++ " of target tree."+        ]++nmatch :: NodeName -> Tree NodeName -> Bool+nmatch n (Node a _) = a == n++findSubTree :: NodeName -> Tree NodeName -> Maybe (Tree NodeName)+findSubTree n n2@(Node x ks)+  | x == n    = Just n2+  | otherwise = case mapMaybe (findSubTree n) ks of+                []    -> Nothing+                (h:_) -> Just h++-- Unique ID++-- | Assigns a unique id to each element of this list, that is, an integer+--   between 1 and the size of the list.+setTidnums :: [TagElem] -> [TagElem]+setTidnums xs = zipWith (\c i -> setOrigin $ c {tidnum = i}) xs [1..]++setOrigin :: TagElem -> TagElem+setOrigin te =+    te { ttree = fmap setLabel . ttree $ te }+  where+    setLabel g = g { gorigin = nameNumber }+    nameNumber = idname te+        `T.append` ":"+        `T.append` (T.pack . show . tidnum) te++-- ----------------------------------------------------------------------+-- TAG Item+-- ----------------------------------------------------------------------++-- | 'TagItem' is a generalisation of 'TagElem'.+class TagItem t where +    tgIdName    :: t -> Text+    tgIdNum     :: t -> Integer+    tgSemantics :: t -> Sem+    tgTree      :: t -> Tree (GNode GeniVal)++instance TagItem TagElem where+    tgIdName = idname+    tgIdNum  = tidnum+    tgSemantics = tsemantics+    tgTree = ttree++-- | Sorts trees into a Map.Map organised by the first literal of their+--   semantics.  This is useful in at least three places: the polarity+--   optimisation, the gui display code, and code for measuring the efficiency+--   of GenI.  Note: trees with a null semantics are filed under an empty+--   predicate, if any.+mapBySem :: (TagItem t) => [t] -> Map.Map (Literal GeniVal) [t]+mapBySem ts = +  let gfn t = case tgSemantics t of+              []    -> emptyLiteral+              (x:_) -> x+  in groupByFM gfn ts++-- ----------------------------------------------------------------------+-- Extracting sentences+-- ----------------------------------------------------------------------++type UninflectedDisjunction = ([Text], Flist GeniVal)++-- | Normally, extracting the sentences from a TAG tree would just+--   consist of reading its leaves.  But if you want the generator to+--   return inflected forms instead of just lemmas, you also need to+--   return the relevant features for each leaf.  In TAG, or at least our+--   use of it, the features come from the *pre-terminal* nodes, that is,+--   not the leaves themselves but their parents.  Another bit of+--   trickiness: because of atomic disjunction, leaves might have more+--   than one value, so we can't just return a String lemma but a list of+--   String, one for each possibility.+tagLeaves :: TagElem -> [ (NodeName, UninflectedDisjunction) ]+tagLeaves te = [ (gnname pt, (getLexeme t, gup pt)) | (pt,t) <- preTerminals . ttree $ te ]++-- | Try in order: lexeme, lexeme attributes, node name+getLexeme :: GNode GeniVal -> [Text]+getLexeme node =+    case glexeme node of+        []   -> fromMaybe [gnname node] $ firstMaybe grab lexemeAttributes+        lexs -> lexs+  where+    grab la = firstMaybe match guppy+      where+        match (AvPair a v) | isConst v && a == la =+             fromFL <$> gConstraints v+        match _ = Nothing+    guppy = gup node++firstMaybe :: (a -> Maybe b) -> [a] -> Maybe b+firstMaybe fn = listToMaybe . mapMaybe fn++-- ----------------------------------------------------------------------+-- Conversion to text+-- ----------------------------------------------------------------------++instance GeniShow TagElem where+    geniShowText te = T.concat+        [ "% ------------------------- ", idname te+        , "\n", ttreename te, ":" , idname te+        , " " , (geniShowText $ tinterface te)+        , " " , (geniShowText $ ttype te)+        , "\n", (geniShowText $ ttree te)+        , "\n", geniKeyword "semantics" (geniShowText $ tsemantics te)+        ]++instance GeniShow [TagElem] where+    geniShowText = T.intercalate "\n\n" . map geniShowText++-- Useful for debugging adjunction and substitution nodes+instance Pretty [TagSite] where+    pretty =+        T.intercalate "\n  " . map fn+      where+        fn (TagSite n t b o) = T.intercalate "/"+            [ n, pretty t, pretty b, o ]++-- ----------------------------------------------------------------------+-- Diagnostic messages+--+-- Diagnostic messages let us know why a TAG tree is not returned as a result.+-- Whenever GenI decides to discard a tree, it sets the tdiagnostic field of +-- the TagElem so that the person using a debugger can find out what went wrong.+-- ----------------------------------------------------------------------++ts_synIncomplete, ts_tbUnificationFailure :: String+ts_synIncomplete = "syntactically incomplete"+ts_tbUnificationFailure = "top/bot unification failure"++ts_rootFeatureMismatch :: Flist GeniVal -> String+ts_rootFeatureMismatch good = "root feature does not unify with " ++ prettyStr good++ts_semIncomplete :: [Literal GeniVal] -> String+ts_semIncomplete sem = "semantically incomplete - missing:  " ++ prettyStr sem++-- ----------------------------------------------------------------------+-- Performance+-- ----------------------------------------------------------------------++{-!+deriving instance NFData TagElem+deriving instance NFData DerivationStep+!-}++-- GENERATED START++ +instance NFData TagElem where+        rnf (TE x1 x2 x3 x4 x5 x6 x7 x8 x9 x10)+          = rnf x1 `seq`+              rnf x2 `seq`+                rnf x3 `seq`+                  rnf x4 `seq`+                    rnf x5 `seq`+                      rnf x6 `seq`+                        rnf x7 `seq` rnf x8 `seq` rnf x9 `seq` rnf x10 `seq` ()++ +instance NFData DerivationStep where+        rnf (SubstitutionStep x1 x2 x3)+          = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` ()+        rnf (AdjunctionStep x1 x2 x3)+          = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` ()+        rnf (InitStep x1) = rnf x1 `seq` ()+-- GENERATED STOP
− src/NLP/GenI/Tags.lhs
@@ -1,380 +0,0 @@-% GenI surface realiser-% Copyright (C) 2005 Carlos Areces and Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.--\chapter{Tags}-\label{cha:Tags}--This module provides basic datatypes specific to Tree Adjoining Grammar-(TAG) and some low-level operations. Note that we don't handle-substitution and adjunction here; see sections \ref{sec:substitution}-and \ref{sec:adjunction} instead.--\begin{code}-{-# LANGUAGE TemplateHaskell #-}--module NLP.GenI.Tags(-   -- Main Datatypes-   Tags, TagElem(..), TagItem(..), TagSite(..),-   TagDerivation, DerivationStep(..), emptyTE,-   ts_synIncomplete, ts_semIncomplete, ts_tbUnificationFailure,-   ts_rootFeatureMismatch,--   -- Functions from Tags-   addToTags, tagLeaves,--   -- Functions from TagElem-   setTidnums, --   -- General functions-   mapBySem, subsumedBy, showTagSites,-   collect, detectSites-) where-\end{code}--\ignore{-\begin{code}-import Control.Applicative ( (<$>), (<*>) )-import qualified Data.Map as Map-import Data.Maybe (fromMaybe, listToMaybe, mapMaybe)-import Data.List (intersperse)-import Data.Tree--import Data.Generics (Data)-import Data.Generics.PlateDirect-import Data.Typeable (Typeable)-import Text.JSON--import NLP.GenI.Btypes (Ptype(Initial, Auxiliar), SemPols,-               GeniVal(GConst), AvPair(..),-               GNode(gup, glexeme, gnname, gaconstr, gdown, gtype, gorigin),-               GType(Subs), Flist,-               DescendGeniVal(..),-               Collectable(..), Idable(..),-               Sem, Pred, emptyPred, -               emptyGNode,-               showFlist, showPairs, showSem, lexemeAttributes,-               )-import NLP.GenI.General (groupByFM, preTerminals)-import NLP.GenI.PolarityTypes (PolarityKey(..))-\end{code}-}--% -----------------------------------------------------------------------\section{Tags}-% ------------------------------------------------------------------------\begin{code}--- | An anchored grammar.---   The grammar associates a set of semantic predicates to a list of trees each.-type Tags = Map.Map String [TagElem]                            ---- | 'addTags' @tags key elem@ adds @elem@ to the the list of elements associated---   to the key-addToTags :: Tags -> String -> TagElem -> Tags-addToTags t k e = Map.insertWith (++) k [e] t-\end{code}--% -----------------------------------------------------------------------\section{TagElem}-% ------------------------------------------------------------------------Final types used for the combined macros + lexicon.  We assume that-a two trees are the same iff they have the same tidnum.  To make this-work, we assign each tree with a unique id during the process of-combining macros with lexicon (see section \ref{sec:combine_macros}).--\begin{code}-data TagSite = TagSite { tsName :: String-                       , tsUp   :: Flist-                       , tsDown :: Flist-                       , tsOrigin :: String-                       }-  deriving (Show, Eq, Ord, Data, Typeable)--instance Biplate TagSite GeniVal where-  biplate (TagSite x1 zu zd x2) = plate TagSite |- x1 ||+ zu ||+ zd |- x2--instance Biplate (Maybe TagSite) GeniVal where-  biplate (Just x1) = plate Just |+ x1-  biplate Nothing   = plate Nothing--data TagElem = TE {-                   idname       :: String,-                   ttreename    :: String,-                   tidnum       :: Integer,-                   ttype        :: Ptype,-                   ttree        :: Tree GNode,-                   tsemantics   :: Sem,-                   -- optimisation stuff-                   -- (polarity key to charge interval)-                   tpolarities  :: Map.Map PolarityKey (Int,Int),-                   tinterface   :: Flist,  -- for idxconstraints (pol)-                   ttrace       :: [String],-                   tsempols     :: [SemPols]-                }-             deriving (Show, Eq, Data, Typeable)--instance Biplate TagElem GeniVal where-  biplate (TE x1 x2 x3 x4 zt zsem x5 zint x6 x7) =-     plate TE |- x1 |- x2 |- x3 |- x4-              |+ zt-              ||+ zsem |- x5-              ||+ zint |- x6 |- x7-\end{code}--A TAG derivation history consists of a list of 3-tuples representing the-operation (s for substitution, a for adjunction), the name of the child tree,-the name of the parent tree and the node affected.--\begin{code}-type TagDerivation = [ DerivationStep ]--data DerivationStep = DerivationStep- { dsOp         :: Char- , dsChild      :: String- , dsParent     :: String- , dsParentSite :: String- } deriving (Show, Ord, Eq)--instance JSON DerivationStep where- readJSON j =-    do jo <- fromJSObject `fmap` readJSON j-       let field x = maybe (fail $ "Could not find: " ++ x) readJSON-                   $ lookup x jo-       DerivationStep <$> field "op"-                      <*> field "child"-                      <*> field "parent"-                      <*> field "parent-node"- showJSON x =-     JSObject . toJSObject $ [ ("op",     showJSON  $ dsOp x)-                             , ("child",  showJSON  $ dsChild x)-                             , ("parent", showJSON  $ dsParent x)-                             , ("parent-node", showJSON $ dsParentSite x)-                             ]-\end{code}--\begin{code}-instance Ord TagElem where-  compare t1 t2 = -    case (ttype t1, ttype t2) of-         (Initial, Initial)   -> compareId -         (Initial, Auxiliar)  -> LT-         (Auxiliar, Initial)  -> GT-         (Auxiliar, Auxiliar) -> compareId -         _                    -> error "TagElem compare not exhaustively defined"-    where compareId  = compare (tidnum t1) (tidnum t2)--instance DescendGeniVal TagElem where-  descendGeniVal s te =-    te { tinterface = descendGeniVal s (tinterface te)-       , ttree      = descendGeniVal s (ttree te)-       , tsemantics = descendGeniVal s (tsemantics te) }--instance DescendGeniVal TagSite where-  descendGeniVal s (TagSite n fu fd o) = TagSite n (descendGeniVal s fu) (descendGeniVal s fd) o--instance Collectable TagElem where-  collect t = (collect $ tinterface t) . (collect $ ttree t) -            . (collect $ tsemantics t)--instance Idable TagElem where-  idOf = tidnum-\end{code}--\begin{code}-emptyTE :: TagElem-emptyTE = TE { idname = "",-               ttreename = "",-               tidnum = -1,-               ttype  = Initial,-               ttree  = Node emptyGNode [],-               tsemantics = [], -               tpolarities = Map.empty,-               tsempols    = [],-               tinterface  = [],-               ttrace = []-             }---- | Given a tree(GNode) returns a list of substitution or adjunction---   nodes, as well as remaining nodes with a null adjunction constraint.-detectSites :: Tree GNode -> ([TagSite], [TagSite], [TagSite])-detectSites t =-  ( sites isSub           -- for substitution-  , sites (not.gaconstr)  -- for adjunction-  , sites constrButNotSub -- for neither-  )- where- ns = flatten t- sites match = [ TagSite (gnname n) (gup n) (gdown n) (gorigin n) | n <- ns, match n ]- isSub n = gtype n == Subs- constrButNotSub n = gaconstr n && (not $ isSub n)-\end{code}--\subsection{Unique ID}--TagElem comparison relies exclusively on \fnparam{tidnum}, so you must-ensure that every TagElem you use has a unique ID.  We provide two-helpful functions for this.  These are most likely useful \emph{between}-lexical selection and generation proper, because during generation-proper, you can simply keep a counter within a State monad to assign-unique IDs to new TagElems.--Note that we also label each node of the tree with its elementary tree-name and with the unique ID.  This helps us to build derivation trees-correctly--\begin{code}--- | Assigns a unique id to each element of this list, that is, an integer---   between 1 and the size of the list.-setTidnums :: [TagElem] -> [TagElem]-setTidnums xs = zipWith (\c i -> setOrigin $ c {tidnum = i}) xs [1..]--setOrigin :: TagElem -> TagElem-setOrigin te = te { ttree = fmap setLabel . ttree $ te }- where setLabel g = g { gorigin = idname te ++ ":" ++ (show.tidnum) te }-\end{code}--% -----------------------------------------------------------------------\section{TAG Item}-% ------------------------------------------------------------------------\begin{code}--- | 'TagItem' is a generalisation of 'TagElem'.-class TagItem t where -  tgIdName    :: t -> String-  tgIdNum     :: t -> Integer-  tgSemantics :: t -> Sem--instance TagItem TagElem where-  tgIdName = idname-  tgIdNum  = tidnum-  tgSemantics = tsemantics-\end{code}--% -----------------------------------------------------------------------\section{Map by sem}-% ------------------------------------------------------------------------\begin{code}--- | Sorts trees into a Map.Map organised by the first literal of their---   semantics.  This is useful in at least three places: the polarity---   optimisation, the gui display code, and code for measuring the efficiency---   of GenI.  Note: trees with a null semantics are filed under an empty---   predicate, if any.-mapBySem :: (TagItem t) => [t] -> Map.Map Pred [t]-mapBySem ts = -  let gfn t = case tgSemantics t of-              []    -> emptyPred-              (x:_) -> x-  in groupByFM gfn ts---- | 'subsumedBy' @cs ts@ determines if the candidate semantics @cs@ is---   subsumed by the proposition semantics @ts@.  Notice how the proposition---   semantics is only a single item where as the candidate semantics is a---   list.------  We assume------  * most importantly that @cs@ has already its semantics instatiated---    (all variables assigned)------  * @cs@ and @ts@ are sorted------  * the list in each element of cs and ts is itself sorted -subsumedBy :: Sem -> Pred -> Bool -subsumedBy [] _ = False -subsumedBy ((ch, cp, cla):cl) (th, tp,tla)-    | (ch == th) && (cp == tp) && (cla == tla) = True -    -- if we haven't yet overshot, try for the next one-    | cp  < tp                   = subsumedBy cl (th, tp, tla)-    | otherwise                  = False-\end{code}--% -----------------------------------------------------------------------\section{Extracting sentences}-% ------------------------------------------------------------------------Normally, extracting the sentences from a TAG tree would just consist of-reading its leaves.  But if you want the generator to return inflected-forms instead of just lemmas, you also need to return the relevant-features for each leaf.  In TAG, or at least our use of it, the features-come from the \emph{pre-terminal} nodes, that is, not the leaves-themselves but their parents.  Another bit of trickiness: because of-atomic disjunction, leaves might have more than one value, so we can't-just return a String lemma but a list of String, one for each-possibility.--\begin{code}-type UninflectedDisjunction = ([String], Flist)--tagLeaves :: TagElem -> [ (String, UninflectedDisjunction) ]-tagLeaves te = [ (gnname pt, (getLexeme t, gup pt)) | (pt,t) <- preTerminals . ttree $ te ]---- | Try in order: lexeme, lexeme attributes, node name-getLexeme :: GNode -> [String]-getLexeme node =-  case glexeme node of-    []   -> fromMaybe [gnname node] $ firstMaybe grab lexemeAttributes-    lexs -> lexs-  where-   grab la =-     let match (AvPair a (GConst v)) | a == la = Just v-         match _ = Nothing-     in firstMaybe match guppy-   guppy      = gup node--firstMaybe :: (a -> Maybe b) -> [a] -> Maybe b-firstMaybe fn = listToMaybe . mapMaybe fn--\end{code}--% -----------------------------------------------------------------------\section{Debugging}-% ------------------------------------------------------------------------\begin{code}--- Useful for debugging adjunction and substitution nodes-showTagSites :: [TagSite] -> String-showTagSites sites = concat $ intersperse "\n  " $ map fn sites-  where-   fn (TagSite n t b o) =-    concat . intersperse "/" $ [ n, showPairs t, showPairs b, o ]-\end{code}--% -----------------------------------------------------------------------\section{Diagnostic messages}-% ------------------------------------------------------------------------Diagnostic messages let us know why a TAG tree is not returned as a result.-Whenever GenI decides to discard a tree, it sets the tdiagnostic field of -the TagElem so that the person using a debugger can find out what went wrong.--\begin{code}-ts_synIncomplete, ts_tbUnificationFailure :: String-ts_synIncomplete = "syntactically incomplete"-ts_tbUnificationFailure = "top/bot unification failure"--ts_rootFeatureMismatch :: Flist -> String-ts_rootFeatureMismatch good = "root feature does not unify with " ++ showFlist good--ts_semIncomplete :: [Pred] -> String-ts_semIncomplete sem = "semantically incomplete - missing:  " ++ showSem sem-\end{code}--% -----------------------------------------------------------------------% Performance-% ----------------------------------------------------------------------
− src/NLP/GenI/Test.hs
@@ -1,31 +0,0 @@--- ------------------------------------------------------------------------- GenI surface realiser--- Copyright (C) 2009 Eric Kow------ This program is free software; you can redistribute it and/or--- modify it under the terms of the GNU General Public License--- as published by the Free Software Foundation; either version 2--- of the License, or (at your option) any later version.------ This program is distributed in the hope that it will be useful,--- but WITHOUT ANY WARRANTY; without even the implied warranty of--- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the--- GNU General Public License for more details.------ You should have received a copy of the GNU General Public License--- along with this program; if not, write to the Free Software--- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.--- ------------------------------------------------------------------------module NLP.GenI.Test where--import System.Environment ( getArgs )-import Test.Framework-import NLP.GenI.GeniVal ( testSuite )--runTests :: IO ()-runTests =- do args <- filter (/= "--unit-tests") `fmap` getArgs-    flip defaultMainWithArgs args-     [ NLP.GenI.GeniVal.testSuite-     ]
+ src/NLP/GenI/TestSuite.hs view
@@ -0,0 +1,46 @@+{-# LANGUAGE OverloadedStrings #-}+--  GenI surface realiser+--  Copyright (C) 2005-2009 Carlos Areces and Eric Kow+--+--  This program is free software; you can redistribute it and/or+--  modify it under the terms of the GNU General Public License+--  as published by the Free Software Foundation; either version 2+--  of the License, or (at your option) any later version.+--+--  This program is distributed in the hope that it will be useful,+--  but WITHOUT ANY WARRANTY; without even the implied warranty of+--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+--  GNU General Public License for more details.+--+--  You should have received a copy of the GNU General Public License+--  along with this program; if not, write to the Free Software+--  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.++module NLP.GenI.TestSuite+where++import Data.Text ( Text)+import qualified Data.Text as T++import NLP.GenI.GeniShow+import NLP.GenI.Pretty+import NLP.GenI.Semantics++data TestCase = TestCase+    { tcName      :: Text+    , tcSemString :: Text -- ^ for gui+    , tcSem       :: SemInput+    , tcExpected  :: [Text] -- ^ expected results (for testing)+    }++instance GeniShow TestCase where+    geniShowText (TestCase { tcName = name+                           , tcExpected = sentences+                           , tcSemString = semStr+                           , tcSem = sem+                           }) =+        T.unlines $ [ name, geniShowText sem ]+            ++ map (geniKeyword "sentence" . squares) sentences++instance Pretty TestCase where+    pretty = geniShowText
+ src/NLP/GenI/TreeSchema.hs view
@@ -0,0 +1,351 @@+-- GenI surface realiser+-- Copyright (C) 2005-2009 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.++{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE OverlappingInstances, FlexibleInstances #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE OverloadedStrings  #-}++-- | This module provides basic datatypes specific to Tree Adjoining Grammar+--   tree schemata.+module NLP.GenI.TreeSchema (+   Macros,+   SchemaTree, SchemaNode, Ttree(..), Ptype(..),++   -- Functions from Tree GNode+   root, rootUpd, foot, setLexeme, setAnchor, lexemeAttributes,+   crushTreeGNode,++   -- GNode+   GNode(..), gnnameIs, NodeName,+   GType(..), gCategory, showLexeme,+   crushGNode,+ ) where++import qualified Data.Map as Map+import Data.Binary+import Data.Tree+import Data.Text ( Text )+import qualified Data.Text as T++import Control.DeepSeq+import Data.FullList hiding (head, tail, (++))+import Data.Generics (Data)+import Data.Typeable (Typeable)++import NLP.GenI.General (filterTree, listRepNode, geniBug, quoteText)+import NLP.GenI.GeniShow+import NLP.GenI.GeniVal ( GeniVal(..), DescendGeniVal(..), Collectable(..),+                        )+import NLP.GenI.FeatureStructure ( AvPair(..), Flist, crushFlist )+import NLP.GenI.Pretty+import NLP.GenI.Semantics ( Sem )++-- ----------------------------------------------------------------------+-- Tree schemata++-- In GenI, the tree schemata are called `macros' for historical reasons.+-- We are working to phase out this name in favour of the more standard+-- `tree schema(ta)'.+-- ----------------------------------------------------------------------++type SchemaTree = Ttree SchemaNode+type SchemaNode = GNode [GeniVal]+type Macros = [SchemaTree]++data Ttree a = TT+    { params  :: [GeniVal]+    , pfamily :: Text+    , pidname :: Text+    , pinterface :: Flist GeniVal+    , ptype :: Ptype+    , psemantics :: Maybe Sem+    , ptrace :: [Text]+    , tree :: Tree a+    }+  deriving (Data, Typeable, Eq)++data Ptype = Initial | Auxiliar+  deriving (Show, Eq, Data, Typeable)++instance DescendGeniVal v => DescendGeniVal (Ttree v) where+  descendGeniVal s mt =+    mt { params = descendGeniVal s (params mt)+       , tree   = descendGeniVal s (tree mt)+       , pinterface  = descendGeniVal s (pinterface mt)+       , psemantics = descendGeniVal s (psemantics mt) }++instance (Collectable a) => Collectable (Ttree a) where+  collect mt = (collect $ params mt) . (collect $ tree mt) .+               (collect $ psemantics mt) . (collect $ pinterface mt)++-- ----------------------------------------------------------------------+-- Tree manipulation+-- ----------------------------------------------------------------------++-- Traversal++instance DescendGeniVal a => DescendGeniVal (Map.Map k a) where+  descendGeniVal s = {-# SCC "descendGeniVal" #-} Map.map (descendGeniVal s)++instance (Collectable a => Collectable (Tree a)) where+  collect = collect.flatten++-- Utility functions++root :: Tree a -> a+root (Node a _) = a++rootUpd :: Tree a -> a -> Tree a+rootUpd (Node _ l) b = (Node b l)++foot :: Tree (GNode a) -> GNode a+foot t = case filterTree (\n -> gtype n == Foot) t of+         [x] -> x+         _   -> geniBug $ "foot returned weird result"++-- | Given a lexical item @s@ and a Tree GNode t, returns the tree t'+--   where l has been assigned to the anchor node in t'+setAnchor :: FullList Text -> Tree (GNode a) -> Tree (GNode a)+setAnchor s t =+  let filt (Node a []) = (gtype a == Lex && ganchor a)+      filt _ = False+  in case listRepNode (setLexeme (fromFL s)) filt [t] of+     ([r],True) -> r+     _ -> geniBug $ "setLexeme " ++ show s ++ " returned weird result"++-- | Given a lexical item @l@ and a tree node @n@ (actually a subtree+--   with no children), return the same node with the lexical item as+--   its unique child.  The idea is that it converts terminal lexeme nodes+--   into preterminal nodes where the actual terminal is the given lexical+--   item+setLexeme :: [Text] -> Tree (GNode a) -> Tree (GNode a)+setLexeme l (Node a []) = Node a [ Node subanc [] ]+  where+    subanc = GN+        { gnname = T.concat $ "_" : gnname a : "." : l+        , gup    = []+        , gdown  = []+        , gaconstr = True+        , ganchor  = False+        , glexeme = l+        , gtype   = Other+        , gorigin = ""+        }+setLexeme _ _ = geniBug "impossible case in setLexeme - subtree with kids"++-- ----------------------------------------------------------------------+-- TAG nodes (GNode)+-- ----------------------------------------------------------------------++-- | A single node of a TAG tree.+data GNode gv = GN+    { gnname :: NodeName+    , gup    :: Flist gv   -- ^ top feature structure+    , gdown  :: Flist gv   -- ^ bottom feature structure+    , ganchor  :: Bool     -- ^ @False@ for na nodes+    , glexeme  :: [Text]   -- ^ @[]@ for na nodes+    , gtype    :: GType+    , gaconstr :: Bool+    , gorigin  :: Text -- ^ for TAG, this would be the elementary tree+                       --   that this node originally came from+    }+  deriving (Eq, Data, Typeable)++-- Node type used during parsing of the grammar+data GType = Subs | Foot | Lex | Other+  deriving (Show, Eq, Data, Typeable)++type NodeName = Text++-- Traversal++instance Collectable gv => Collectable (GNode gv) where+  collect n = (collect $ gdown n) . (collect $ gup n)++instance DescendGeniVal v => DescendGeniVal (GNode v) where+  descendGeniVal s gn =+    gn { gup = descendGeniVal s (gup gn)+       , gdown = descendGeniVal s (gdown gn) }++-- Utilities++gnnameIs :: NodeName -> GNode gv -> Bool+gnnameIs n = (== n) . gnname++-- | Return the value of the "cat" attribute, if available+gCategory :: Flist GeniVal -> Maybe GeniVal+gCategory top =+  case [ v | AvPair "cat" v <- top ] of+  []  -> Nothing+  [c] -> Just c+  _   -> geniBug $ "Impossible case: node with more than one category"++-- | Attributes recognised as lexemes, in order of preference+lexemeAttributes :: [Text]+lexemeAttributes = [ "lex", "phon", "cat" ]++-- ----------------------------------------------------------------------+-- Pretty printing and other text conversions+-- ----------------------------------------------------------------------++instance GeniShow Ptype where+    geniShow Initial  = "initial"+    geniShow Auxiliar = "auxiliary"++instance (GeniShow a) => GeniShow (Ttree a) where+    geniShowText tt = T.intercalate "\n" . filter (not . T.null) $+        [ "% ------------------------- ", pidname tt+        , T.unwords [ pfamily tt <> ":" <> pidname tt+                    , plist+                    , geniShowText (ptype  tt)+                    ]+        , geniShowText (tree   tt)+        , maybe "" showSem (psemantics tt)+        , showTr (ptrace tt)+        ]+      where+        plist = parens . T.unwords . concat $+            [ map geniShowText (params tt)+            , ["!"]+            , map geniShowText (pinterface tt)+            ]+        showSem = geniKeyword "semantics" . geniShowText+        showTr  = geniKeyword "trace" . squares . T.unwords++-- | The default show for GNode tries to be very compact; it only shows the value+--   for cat attribute and any flags which are marked on that node.+--+--   This is one the places where the pretty representation of a GenI object is+--   different from its GenI-format one+instance Pretty (GNode GeniVal) where+    pretty gn =+        stub `T.append` extra+      where+        cat_ = maybe "" pretty . gCategory $ gup gn+        lex_ = showLexeme (glexeme gn)+        --+        stub = T.intercalate ":" $ filter (not . T.null) [ cat_, lex_ ]+        extra = case gtype gn of+                    Subs -> " !"+                    Foot -> " *"+                    _    -> if gaconstr gn then " #"   else ""++instance GeniShow (GNode GeniVal) where+    geniShowText x =+        T.unwords . filter (not . T.null) $+            [ gnname x, gaconstrstr, gtypestr x, glexstr x, tbFeats x ]+      where+        gaconstrstr = case (gaconstr x, gtype x) of+                          (True, Other) -> "aconstr:noadj"+                          _             ->  ""+        gtypestr n  = case gtype n of+                          Subs -> "type:subst"+                          Foot -> "type:foot"+                          Lex  -> if ganchor n && (null.glexeme) n+                                     then "type:anchor" else "type:lex"+                          _    -> ""+        glexstr n =+            if null ls+               then ""+               else T.intercalate "|" (map quoteText ls)+          where+            ls = glexeme n+        tbFeats n =+            geniShowText (gup n)+            `T.append` "!"+            `T.append` geniShowText (gdown n)+++-- FIXME: will have to think of nicer way - one which involves+-- unpacking the trees :-(+showLexeme :: [Text] -> Text+showLexeme []   = ""+showLexeme [l]  = l+showLexeme xs   = T.intercalate "|" xs++-- Fancy disjunction++crushTreeGNode :: Tree (GNode [GeniVal]) -> Maybe (Tree (GNode GeniVal))+crushTreeGNode (Node x xs) =+ do x2  <- crushGNode x+    xs2 <- mapM crushTreeGNode xs+    return $ Node x2 xs2++crushGNode :: GNode [GeniVal] -> Maybe (GNode GeniVal)+crushGNode gn =+  do gup2   <- crushFlist (gup gn)+     gdown2 <- crushFlist (gdown gn)+     return $ GN { gnname = gnname gn+                 , gup = gup2+                 , gdown = gdown2+                 , ganchor = ganchor gn+                 , glexeme = glexeme gn+                 , gtype = gtype gn+                 , gaconstr = gaconstr gn+                 , gorigin = gorigin gn}+++instance Binary Ptype where+  put Initial = putWord8 0+  put Auxiliar = putWord8 1+  get = do+    tag_ <- getWord8+    case tag_ of+      0 -> return Initial+      1 -> return Auxiliar+      _ -> fail "no parse"++instance Binary gv => Binary (GNode gv) where+  put (GN a b c d e f g h) = put a >> put b >> put c >> put d >> put e >> put f >> put g >> put h+  get = get >>= \a -> get >>= \b -> get >>= \c -> get >>= \d -> get >>= \e -> get >>= \f -> get >>= \g -> get >>= \h -> return (GN a b c d e f g h)++instance Binary GType where+  put Subs = putWord8 0+  put Foot = putWord8 1+  put Lex = putWord8 2+  put Other = putWord8 3+  get = do+    tag_ <- getWord8+    case tag_ of+      0 -> return Subs+      1 -> return Foot+      2 -> return Lex+      3 -> return Other+      _ -> fail "no parse"++instance (Binary a) => Binary (Ttree a) where+  put (TT a b c d e f g h) = put a >> put b >> put c >> put d >> put e >> put f >> put g >> put h+  get = get >>= \a -> get >>= \b -> get >>= \c -> get >>= \d -> get >>= \e -> get >>= \f -> get >>= \g -> get >>= \h -> return (TT a b c d e f g h)++-- Node type used during parsing of the grammar+instance NFData GType where+  rnf x = x `seq` ()++instance NFData Ptype where+  rnf x = x `seq` ()++-- | A single node of a TAG tree.+instance NFData gv => NFData (GNode gv) where+  rnf (GN x1 x2 x3 x4 x5 x6 x7 x8)+          = rnf x1 `seq`+              rnf x2 `seq`+                rnf x3 `seq`+                  rnf x4 `seq`+                    rnf x5 `seq`+                      rnf x6 `seq`+                        rnf x7 `seq` rnf x8 `seq` ()
+ src/NLP/GenI/Warning.hs view
@@ -0,0 +1,32 @@+-- GenI surface realiser+-- Copyright (C) 2012 Eric Kow (Computational Linguistics Ltd)+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.++-- | Typed warnings as an easier alternative to strings.+--+--   This makes it easier to recognise repeated warnings and print them+--   out in a reasonable way+module NLP.GenI.Warning+    ( -- * Collection of warnings+      GeniWarnings, fromGeniWarnings, mkGeniWarnings+    , sortWarnings+      -- * Individual warnings+    , GeniWarning(..), LexWarning(..)+    , showGeniWarning+    )+ where++import NLP.GenI.Warning.Internal
+ src/NLP/GenI/Warning/Internal.hs view
@@ -0,0 +1,146 @@+-- GenI surface realiser+-- Copyright (C) 2011 Eric Kow (on behalf of SRI)+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.++{-# LANGUAGE OverloadedStrings #-}+module NLP.GenI.Warning.Internal where++import Data.FullList ( FullList, fromFL )+import Data.List+import Data.Monoid ( Monoid, mconcat, mappend, mempty )+import Data.Text ( Text )+import qualified Data.Map as Map+import qualified Data.Text as T++import Data.Poset++import NLP.GenI.General ( histogram )+import NLP.GenI.GeniVal ( GeniVal )+import NLP.GenI.LexicalSelection.Types ( LexCombineError, showLexCombineError )+import NLP.GenI.Lexicon ( LexEntry(..) )+import NLP.GenI.Pretty+import NLP.GenI.Semantics ( Literal )+import NLP.GenI.TreeSchema ( showLexeme )++-- | This exists because we want the 'Monoid' instance, providing a +--   GenI-specific notion of appending which merges instances of the+--   same error+newtype GeniWarnings = GeniWarnings { fromGeniWarnings :: [GeniWarning] }++mkGeniWarnings :: [GeniWarning] -> GeniWarnings+mkGeniWarnings = mconcat . map (\x -> GeniWarnings [x])++instance Monoid GeniWarnings where+  mempty  = GeniWarnings []+  mappend (GeniWarnings g1) (GeniWarnings g2) = GeniWarnings (foldr appendWarning g2 g1)++data GeniWarning = -- | A warning that should be repeated for each lexical entry affected+                   LexWarning [LexEntry] LexWarning+                   -- | A single custom warning+                 | CustomLexWarning Text+                   -- | Literals which did not receive any lexical selection+                 | NoLexSelection         [Literal GeniVal]+                   -- | Warnings from the morphological realiser+                 | MorphWarning           [Text]+  deriving (Eq)+++data LexWarning = LexCombineAllSchemataFailed+                | LexCombineOneSchemaFailed   LexCombineError+                | MissingCoanchors            Text Int+  deriving (Eq)++-- | Sort, treating non-comporable items as equal+posort :: Poset a => [a] -> [a]+posort = sortBy (flip fromPosetCmp)+ where+  fromPosetCmp x1 x2 = case posetCmp x1 x2 of+                         Comp o -> o+                         NComp  -> EQ++instance Poset GeniWarning where+ -- 1. LexWarning+ leq (LexWarning _ w1) (LexWarning _ w2)  = leq w1 w2+ leq (LexWarning _ _)  _                  = True+ -- 2. CustomLexWarning+ leq (CustomLexWarning _)  (LexWarning _ _)      = False+ leq (CustomLexWarning w1) (CustomLexWarning w2) = leq w1 w2+ leq (CustomLexWarning _)  _                     = True+ -- 3. NoLexSelection+ leq (NoLexSelection _) (LexWarning _ _)     = False+ leq (NoLexSelection _) (CustomLexWarning _) = False+ leq (NoLexSelection _) (NoLexSelection _)   = True+ leq (NoLexSelection _) _                    = True+ -- 4. MorphWarning+ leq (MorphWarning _)  (LexWarning _ _)     = False+ leq (MorphWarning _)  (CustomLexWarning _) = False+ leq (MorphWarning _)  (NoLexSelection _)   = False+ leq (MorphWarning w1) (MorphWarning w2)    = leq w1 w2++instance Poset LexWarning where+ -- 1. LexCombineOneSchemaFailed+ leq (LexCombineOneSchemaFailed l1) (LexCombineOneSchemaFailed l2)   = leq l1 l2+ leq (LexCombineOneSchemaFailed _)  _                                = True+ -- 2. LexCombineAllSchemataFailed+ leq LexCombineAllSchemataFailed (LexCombineOneSchemaFailed _)       = False+ leq LexCombineAllSchemataFailed  _                                  = True+ -- 3. MissingCoanchors+ leq (MissingCoanchors _ n1) (MissingCoanchors _ n2)                 = leq n1 n2+ leq (MissingCoanchors _ _) (LexCombineOneSchemaFailed _)            = False+ leq (MissingCoanchors _ _) LexCombineAllSchemataFailed              = False++sortWarnings :: GeniWarnings -> GeniWarnings+sortWarnings (GeniWarnings ws) = GeniWarnings (posort ws)++appendWarning :: GeniWarning -> [GeniWarning] -> [GeniWarning]+appendWarning w0 []     = [w0]+appendWarning w0 (w:ws) = case mergeWarning w0 w of+                            Just w1 -> w1 : ws+                            Nothing -> w  : appendWarning w0 ws++mergeWarning :: GeniWarning -> GeniWarning -> Maybe GeniWarning+mergeWarning (LexWarning ls1 w1) (LexWarning ls2 w2) | w1 == w2 = Just (LexWarning (ls1 ++ ls2) w1)+mergeWarning _ _ = Nothing++-- | A warning may be displayed over several lines+showGeniWarning :: GeniWarning -> [Text]+showGeniWarning (NoLexSelection ps) =+    [ "No lexical entries for literals:" <+> T.unwords (map pretty ps) ]+showGeniWarning (CustomLexWarning w) = [w]+showGeniWarning (LexWarning ls wa)  = do -- list monad+    wf <- Map.toList (toWfCount ls)+    return (msg <> ":" <+> prettyCount showWithFam "lemmas" wf <> suffix)+ where+    (msg, suffix) = showLexWarning wa+    showLexWarning LexCombineAllSchemataFailed =+        ("Lexically selected but anchoring failed for *all* instances of", "")+    showLexWarning (LexCombineOneSchemaFailed lc) =+        showLexCombineError lc+    showLexWarning (MissingCoanchors co n) =+        (T.unwords [ "Expected co-anchor", co+                   , "is missing from", T.pack (show n), "schemata"+                   ]+        , "")+    showWithFam (w, f) = showLexeme (fromFL w) <+> parens f+showGeniWarning (MorphWarning ws) = map ("Morph:" <+>) ws++-- word and all families associated with that word+type WordFamilyCount = Map.Map (FullList Text, Text) Int++toWfCount :: [LexEntry] -> WordFamilyCount+toWfCount = histogram . map toWf+ where+   toWf i = (iword i, ifamname i)