mirror of
https://github.com/GrammaticalFramework/gf-core.git
synced 2026-04-17 08:49:31 -06:00
194 lines
6.8 KiB
Haskell
194 lines
6.8 KiB
Haskell
{-# LANGUAGE FlexibleInstances,
|
|
MultiParamTypeClasses,
|
|
ScopedTypeVariables,
|
|
FlexibleContexts,
|
|
UndecidableInstances #-}
|
|
module MonadSP ( Rule(..), Grammar, grammar
|
|
, P, parse
|
|
, cat, word, word2, lemma, inside, insideSuff, transform
|
|
, many, many1, opt
|
|
, optEat, consume, wordlookup,write
|
|
) where
|
|
import Data.Tree
|
|
import Data.Char
|
|
import Data.List
|
|
import qualified Data.Map as Map
|
|
import Control.Monad
|
|
import Control.Monad.State
|
|
import Control.Monad.Writer
|
|
import PGF hiding (Tree,parse)
|
|
|
|
|
|
infix 1 :->
|
|
|
|
|
|
data Rule m t e = t :-> P t e m e
|
|
type Grammar m t e = t -> PGF -> Morpho -> [Tree t] -> m e
|
|
|
|
instance Show t => Show (Rule m t e) where
|
|
show (t :-> x) = show t
|
|
|
|
|
|
grammar :: (MonadWriter [String] m,MonadState s m,Ord t,Show t,Show e)
|
|
=> ([e] -> e) -> [Rule m t e] -> Grammar m t e
|
|
grammar def rules = gr
|
|
where
|
|
gr = \tag -> do
|
|
|
|
let retry = \pgf m ts -> case ts of
|
|
[Node w []] -> return (def [])
|
|
trs -> def `liftM` sequence [ gr tag pgf m trs'
|
|
| Node tag trs' <- trs]
|
|
|
|
case Map.lookup tag pmap of
|
|
Just f -> \pgf m ts -> do
|
|
stored <- get
|
|
r <- unP f gr pgf m ts
|
|
case r of
|
|
Just (e,[]) -> return e
|
|
Just (e,xs) -> tell ["Rest parse"] >> retry pgf m ts -- use xs here?
|
|
Nothing -> put stored >> retry pgf m ts
|
|
Nothing -> retry
|
|
|
|
-- If many rules match, try all of them (mplus)
|
|
pmap = Map.fromListWith mplus (map (\(t :-> r) -> (t,r)) rules)
|
|
|
|
newtype P t e m a = P {unP :: Grammar m t e -> PGF -> Morpho -> [Tree t] -> m (Maybe (a,[Tree t]))}
|
|
|
|
instance Monad m => Monad (P t e m) where
|
|
return x = P $ \gr pgf m ts -> return (Just (x,ts))
|
|
f >>= g = P $ \gr pgf m ts -> unP f gr pgf m ts >>= \r -> case r of
|
|
Just (x,ts') -> unP (g x) gr pgf m ts'
|
|
Nothing -> return Nothing
|
|
|
|
instance MonadState s m => MonadPlus (P t e m) where
|
|
mzero = P $ \gr pgf m ts -> return Nothing
|
|
mplus f g = P $ \gr pgf m ts -> do
|
|
store <- get
|
|
res <- unP f gr pgf m ts
|
|
case res of
|
|
Just x -> return (Just x)
|
|
Nothing -> put store >> unP g gr pgf m ts
|
|
|
|
instance MonadState s m => MonadState s (P t e m) where
|
|
put s = P $ \gr pgf m ts -> put s >> return (Just ((),ts))
|
|
get = P $ \gr pgf m ts -> get >>= \s -> return (Just (s,ts))
|
|
|
|
instance MonadWriter w m => MonadWriter w (P t e m) where
|
|
tell w = P $ \gr pgf m ts -> tell w >> return (Just ((),ts))
|
|
listen = error "listen not implemented for P"
|
|
pass = error "pass not implemented for P"
|
|
|
|
-- write x = tell [x]
|
|
write :: MonadWriter [w] m => w -> P t e m ()
|
|
write = tell . return
|
|
|
|
instance MonadTrans (P t e) where
|
|
lift m = P $ \gr p morpho ts -> m >>= \r -> return (Just (r,ts))
|
|
|
|
parse :: Monad m => Grammar m t e -> PGF -> Morpho -> Tree t -> m e
|
|
parse gr pgf morpho (Node tag ts) = gr tag pgf morpho ts
|
|
|
|
silent m = (m,[])
|
|
speak s (m,w) = (m,s:w)
|
|
speaks s (m,w) = (m,s++w)
|
|
addS s m = (m,s)
|
|
add s m = (m,[s])
|
|
|
|
|
|
cat :: (Monad m,Eq t,Show t) => [t] -> P [t] e m e
|
|
cat tag = P $ \gr pgf morpho ts ->
|
|
case ts of
|
|
Node tag1 ts1 : ts | tag `isPrefixOf` tag1
|
|
-> gr tag1 pgf morpho ts1 >>= \r -> return (Just (r,ts))
|
|
_ -> return Nothing
|
|
|
|
word :: (Monad m,Show t,Eq t) => [t] -> P [t] e m [t]
|
|
word tag = P $ \gr pgf morpho ts -> return $
|
|
case ts of
|
|
(Node tag1 [Node w []] : ts) | tag `isPrefixOf` tag1
|
|
-> Just (w,ts)
|
|
_ -> Nothing
|
|
|
|
|
|
word2 :: (Monad m,Eq t) => t -> P t e m t
|
|
word2 tag = P $ \gr pgf morpho ts -> return $
|
|
case ts of
|
|
(Node tag1 [Node tag2 [Node w []]] : ts) | tag == tag1 -> Just (w,ts)
|
|
_ -> Nothing
|
|
|
|
|
|
inside, insideSuff :: (MonadWriter [String] m,Eq t,Show t)=> [t] -> P [t] e m a -> P [t] e m a
|
|
insideSuff = inside' isSuffixOf
|
|
inside = inside' isPrefixOf
|
|
|
|
inside' :: (MonadWriter [String] m,Eq t,Show t)=>
|
|
([t] -> [t] -> Bool) -> [t] -> P [t] e m a -> P [t] e m a
|
|
inside' isEq tag f = P $ \gr pgf morpho ts ->
|
|
case ts of
|
|
Node tag1 ts1 : ts | tag `isEq` tag1 -> do
|
|
tell [show tag++" "++show tag1]
|
|
unP f gr pgf morpho ts1 >>= \r -> case r of
|
|
Just (x,[]) -> return (Just (x,ts))
|
|
Just (x,xs) -> tell ["inside fail "++show xs] >> return Nothing
|
|
Nothing -> return Nothing
|
|
_ -> return Nothing
|
|
|
|
|
|
magicLookup :: String -> String -> String -> Morpho -> PGF -> [Lemma]
|
|
magicLookup w cat0 an0 morpho pgf = [ lem
|
|
| (lem, an1) <- lookupMorpho morpho (map toLower w)
|
|
, let cat1 = maybe "" (showType []) (functionType pgf lem)
|
|
, cat0 == cat1 && an0 == an1
|
|
]
|
|
|
|
wordlookup :: MonadWriter [String] m => String -> String -> String -> P String e m CId
|
|
wordlookup w cat0 an0 = P $ \gr pgf morpho ts -> do
|
|
tell ["wordlookup: " ++ w ++ show ts ++ show cat0]
|
|
let wds = magicLookup w cat0 an0 morpho pgf
|
|
tell [show wds]
|
|
case wds of
|
|
(wd:_) -> return $ Just (wd,ts)
|
|
[] -> return Nothing
|
|
|
|
|
|
lemma :: MonadWriter [String] m => String -> String -> P String e m CId
|
|
lemma cat = liftM head . lemmas cat
|
|
|
|
lemmas :: MonadWriter [String] m => String -> String -> P String e m [CId]
|
|
lemmas cat0 an0 = P $ \gr pgf morpho ts -> do
|
|
tell ["lemma: "++show ts++show cat0]
|
|
case ts of
|
|
Node w [] : ts -> case magicLookup w cat0 an0 morpho pgf of
|
|
(id:ids) -> tell ["lemma ok"] >> return (Just (id:ids,ts))
|
|
_ -> tell ["no word "++w++cat0++an0] >> return Nothing
|
|
_ -> tell ["tried to lemma a tag"] >> return Nothing
|
|
|
|
|
|
transform :: Monad m => ([Tree t] -> [Tree t]) -> P t e m ()
|
|
transform f = P $ \gr pgf morpho ts -> return (Just ((),f ts))
|
|
|
|
many :: MonadState s m => P t e m a -> P t e m [a]
|
|
many f = many1 f
|
|
`mplus`
|
|
return []
|
|
|
|
many1 :: MonadState s m => P t e m a -> P t e m [a]
|
|
many1 f = do x <- f
|
|
xs <- many f
|
|
return (x:xs)
|
|
|
|
opt :: MonadState s m => P t e m a -> a -> P t e m a
|
|
opt f x = mplus f (return x)
|
|
|
|
optEat :: MonadState s m => P t e m a -> a -> P t e m a
|
|
optEat f x = mplus f (consume >> return x)
|
|
|
|
|
|
consume :: Monad m => P t e m ()
|
|
consume = P $ \gr pgf morpho ts ->
|
|
case ts of
|
|
Node x w:ws -> return (Just ((),ws))
|
|
[] -> return (Just ((),[]))
|
|
|