gpt4 book ai didi

haskell - 如何使用与另一个 Parsec 解析器具有不同流类型的 Parsec 解析器?

转载 作者:行者123 更新时间:2023-12-02 02:38:49 25 4
gpt4 key购买 nike

我有一个用 Text 编写的解析器作为流类型,而默认为 Text.Parsec.String模块使用 String除此以外。
如何在 Parsec Text b c 的上下文中使用自定义编写的解析器 ( Parsec String b c ) ?
本质上,我似乎需要这样的功能:

f :: Parsec Text b c -> Parsec String b c
f = undefined
虽然听起来可能,但做起来似乎很复杂。

最佳答案

这很可怕,但相对简单。这个想法是使用低级函数runParsecTmkPT解构和重建解析器,用适配器将其括起来以修改传入和传出状态的流类型:

import Text.Parsec
import Data.Text (Text)
import qualified Data.Text as Text

stringParser :: (Monad m) => ParsecT Text u m a -> ParsecT String u m a
stringParser p = mkPT $ \st -> (fmap . fmap . fmap) outReply $ runParsecT p (inState st)
where inState :: State String u -> State Text u
inState (State i pos u) = State (Text.pack i) pos u
outReply :: Reply Text u a -> Reply String u a
outReply (Ok a (State i pos u) e) = Ok a (State (Text.unpack i) pos u) e
outReply (Error e) = Error e
它似乎工作正常:
myTextParser :: Parsec Text () String
myTextParser = (:) <$> oneOf "abc" <*> many letter

myStringParser :: Parsec String () (String, String)
myStringParser = (,) <$> p <* spaces <*> p
where p = stringParser myTextParser

main = do
print =<< parseTest myStringParser "avocado butter"
print =<< parseTest myStringParser "apple error"
给予:
λ> main
("avocado","butter")
()
parse error at (line 1, column 7):
unexpected "e"
expecting space
()
然而 ,这里可能存在一些严重的性能问题,除非这是在小型玩具解析器中使用。 pack调用将获取整个传入流并将其转换为 Text值(value)。如果你从一个懒惰的 String 解析(例如,来自惰性 I/O 调用),第一次使用转换的解析器会将整个字符串作为 Text 读入内存。并将其作为 String 抽回;对同一解析器的进一步调用会将剩余的流重新打包为 Text每一次。切换到懒惰 Text不会真的有帮助,因为 pack仍然将整个输入打包到“懒惰” Text值(value)。
您需要运行一些测试/基准测试,以查看您的应用程序是否可以接受这种性能影响。一般来说,重写 Text解析器(或查看它是否会使用抽象流类型编译)将是一种更好的方法。
完整代码示例:
{-# OPTIONS_GHC -Wall #-}

import Text.Parsec
import Data.Text (Text)
import qualified Data.Text as Text

stringParser :: (Monad m) => ParsecT Text u m a -> ParsecT String u m a
stringParser p = mkPT $ \st -> (fmap . fmap . fmap) outReply $ runParsecT p (inState st)
where inState :: State String u -> State Text u
inState (State i pos u) = State (Text.pack i) pos u
outReply :: Reply Text u a -> Reply String u a
outReply (Ok a (State i pos u) e) = Ok a (State (Text.unpack i) pos u) e
outReply (Error e) = Error e

myTextParser :: Parsec Text () String
myTextParser = (:) <$> oneOf "abc" <*> many letter

myStringParser :: Parsec String () (String, String)
myStringParser = (,) <$> p <* spaces <*> p
where p = stringParser myTextParser

main = do
print =<< parseTest myStringParser "avocado butter"
print =<< parseTest myStringParser "apple error"

关于haskell - 如何使用与另一个 Parsec 解析器具有不同流类型的 Parsec 解析器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63317161/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com