Я использую каналы, attoparsec и pipe-attoparsec, чтобы написать конвертер файла дампа базы данных. Общий формат файла состоит в том, чтобы иметь команду создания таблицы, за которой следует необязательная команда вставки. В дополнение к преобразованию операторов на месте определения таблиц должны храниться в памяти до самого конца для дополнительной обработки (индексы, ограничения и т. д.).
Это прекрасно работает, но теперь мне нужно разрешить некоторым из моих внутренних синтаксических анализаторов доступ к состоянию моего производителя, чтобы определить, какой синтаксический анализатор необходимо запустить при обработке значений из команды вставки.
Я пробовал что-то вроде этого:
-- IO
import qualified Data.ByteString.Char8 as BS (putStrLn)
import System.Exit (ExitCode (..), exitSuccess, exitFailure)
import System.IO (hPutStrLn, stderr)
-- Pipes
import Pipes (runEffect, for, liftIO, Producer, Effect)
import Pipes.Attoparsec (parsed, ParsingError)
import Pipes.Lift (runStateP)
import Pipes.Safe (runSafeT)
import qualified Pipes.ByteString as PBS (stdin)
-- State
import Control.Monad.Trans.Class (lift)
import Control.Monad.Trans.State.Strict
dump' :: StateT ParserState Parser Command
dump' = fmap Create createStatements' <|> fmap Insert justData'
doStuff :: MonadIO m => Effect m (Either (ParsingError, Producer ByteString (StateT ParserState m) ()) (), ParserState)
doStuff = runStateP defaultParserState theStuff
theStuff :: MonadIO m => Effect (StateT ParserState m) (Either (ParsingError, Producer ByteString (StateT ParserState m) ()) ())
theStuff = for runParser (liftIO . BS.putStrLn <=< lift . processCommand)
runParser :: MonadIO m => Producer Command (StateT ParserState m) (Either (ParsingError, Producer ByteString (StateT ParserState m) ()) ())
runParser = do
s <- lift get
liftIO $ putStrLn "runParser"
liftIO $ putStrLn $ show s
parsed (evalStateT dump' s) PBS.stdin
processCommand :: MonadIO m => Command -> StateT ParserState m ByteString
processCommand (Create xs) = do
currentState <- get
liftIO $ putStrLn "processCommand"
liftIO $ putStrLn $ show currentState
_ <- put (currentState { constructs = xs ++ (constructs currentState)})
return $ P.firstPass $ P.transformConstructs xs
processCommand (Insert x) = return x
Полный исходный код (включая парсеры): https://github.com/cimmanon/mysqlnothx/blob/parser-state/src/Main.hs
Когда я запускаю его, я получаю результат, который выглядит примерно так:
runParser
ParserState {constructs = []}
processCommand
ParserState {constructs = []}
processCommand
ParserState {constructs = [ ... ]}
processCommand
ParserState {constructs = [ ..... ]}
Я ожидал, что runParser (который будет получать последнее содержимое из State) будет запускаться каждый раз, когда запускается processCommand, но это явно не так, судя по выходным данным. Когда я проверяю содержимое State в синтаксическом анализаторе, оно всегда пусто, независимо от того, сколько команд анализируется.
Как я могу расширить состояние от моих производителей до моего парсера (дампа), чтобы они использовали одно и то же состояние? Если у моего производителя есть 4 значения в состоянии, синтаксический анализатор также должен увидеть те же самые 4 значения.
Parser
? - person danidiaz   schedule 01.05.2017pipes-autoparsec
требуется быть автопарсекомByteString
Parser
а>. Я понял, какой из них по аргументуProducer
вернул ошибкуrunParser
. - person Cirdec   schedule 01.05.2017