Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 将状态从生产者传递到解析器_Haskell_Haskell Pipes_Attoparsec - Fatal编程技术网

Haskell 将状态从生产者传递到解析器

Haskell 将状态从生产者传递到解析器,haskell,haskell-pipes,attoparsec,Haskell,Haskell Pipes,Attoparsec,我正在使用pipes、attoparsec和pipes-attoparsec编写一个数据库转储文件转换器。该文件的一般格式是先有一个CREATETABLE命令,然后是一个可选的insert命令。除了就地转换语句外,表定义还必须保存在内存中,直到最后进行额外处理(索引、约束等) 这很好,但是现在我需要允许一些内部解析器访问生产者的状态,以便在处理insert命令中的值时确定需要运行哪个解析器 我试过这样的方法: -- IO import qualified Data.ByteString.Char

我正在使用pipes、attoparsec和pipes-attoparsec编写一个数据库转储文件转换器。该文件的一般格式是先有一个CREATETABLE命令,然后是一个可选的insert命令。除了就地转换语句外,表定义还必须保存在内存中,直到最后进行额外处理(索引、约束等)

这很好,但是现在我需要允许一些内部解析器访问生产者的状态,以便在处理insert命令中的值时确定需要运行哪个解析器

我试过这样的方法:

-- 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
runParser
ParserState {constructs = []}
processCommand
ParserState {constructs = []}
processCommand
ParserState {constructs = [ ... ]}
processCommand
ParserState {constructs = [ ..... ]}
我希望每次processCommand运行时都会运行runParser(它将从State获取最新的内容),但根据输出情况显然不是这样。当我在解析器中检查State的内容时,无论解析了多少个命令,它总是空的

如何将状态从生产者扩展到解析器(dump'),以便它们共享相同的状态?如果我的生产者在状态中有4个值,那么解析器也应该看到这4个值

我希望每次运行
processCommand
时都能运行
runParser
(它将从State获取最新的内容),但情况显然不是这样

您的主要作用是runParser(liftIO.BS.putStrLn)的

我希望每次运行
processCommand
时都能运行
runParser
(它将从State获取最新的内容),但情况显然不是这样


你的主要作用是运行解析器的
(liftIO.BS.putStrLn)你从哪里得到你的
解析器
类型?@danidiaz,因为它需要是一个autoparsec
ByteString
。我通过
生产者
运行解析器
@danidiaz的错误中返回的参数判断出是哪一个(Data.Attoparsec.ByteString)。你从哪里得到你的
解析器
类型?@danidiaz,因为它需要是一个autoparsec
ByteString
。我通过
Producer
返回的
runParser
@danidiaz的
runParser
错误中的
参数找出了哪个是来自Attoparsec(Data.Attoparsec.ByteString)。这确实解释了我所看到的行为,但是否有可能实现我所寻找的行为?如果有必要,我准备重写我的解析器,以使其工作方式有所不同,但我希望节省自己几个小时的工作。@cimmanon我不确定从您的问题中可以看出您所寻找的行为是什么。也许作为两个问题,提问会更容易一些estions,“我的代码为什么要这样做?”,重点介绍现有代码的描述-就像这个代码一样,以及“我如何让它做X”?专注于您想要完成的X的描述。@cimmanon但这里有一个提示:如果您想在所有
命令
s被解析后在末尾做其他事情,请尝试在
runParser
s的末尾添加一些行(就像
s'一样,它是Insert分支的下游解析器,需要访问到目前为止解析的表定义,以便我可以为每种列类型运行正确的解析器(基本上保证是create table,然后为该表插入,但我捕获的其他create语句可以出现在类似索引之间)。生成我正在分析的转储的数据库生成无效的日期,并且二进制类型的格式不正确…它们看起来与普通的带引号的字符串无法区分。如果您不知道我是在问“X为什么这样做?”还是“我如何做X?”,你应该要求澄清,而不是发布答案。因为我的问题从来不是“X为什么这样做?”,我已经可以根据输出推断出行为。这确实解释了我看到的行为,但有可能实现我想要的行为吗?如果有必要,我准备重写我的解析器以使其工作方式不同,但我希望节省自己几个小时的工作。@cimmanon从你的问题中我不确定你的行为是什么e寻找的是。也许可以更容易地问两个问题,“我的代码为什么会这样做?”,重点是对现有代码的描述——就像这一个,以及“我如何才能让它做X”?专注于您想要完成的X的描述。@cimmanon但这里有一个提示:如果您想在所有
命令
s被解析后在末尾做其他事情,请尝试在
runParser
s的末尾添加一些行(就像
s'一样,它是Insert分支的下游解析器,需要访问到目前为止解析的表定义,以便我可以为每种列类型运行正确的解析器(基本上保证是create table,然后为该表插入,但我捕获的其他create语句可以出现在类似索引之间)。生成我正在分析的转储的数据库生成无效的日期,并且二进制类型的格式不正确…它们看起来与普通的带引号的字符串无法区分。如果您不知道我是在问“X为什么这样做?”还是“我如何做X?”,您应该要求澄清,而不是发布答案。因为我的问题从来不是“X为什么这样做?”,我已经可以根据输出推断出行为。
runParser = do
    s <- lift get
    liftIO $ putStrLn "runParser"
    liftIO $ putStrLn $ show s
    parsed (evalStateT dump' s) PBS.stdin