我正在尝试为自定义文件格式创建解析器。在我正在使用的格式中,某些字段具有如下的结束标记:
<SOL>
<DATE>0517
<YEAR>86
</SOL>
我试图获取</
和>
之间的值,并将其用作更大解析器的一部分。
我已经提出了以下代码。问题是,解析器返回[Char]
而不是Text
。我可以通过执行Char
打包每个fmap pack $ return r
以获取文本值,但我希望类型推断可以使我不必这样做。有人可以提示我为什么要回来[Char]
而不是Text
,以及如何在不必手动打包价值的情况下取回Text
?
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE OverloadedStrings #-}
import Data.Text
import Text.Parsec
import Text.Parsec.Text
-- |A closing tag is on its own line and is a "</" followed by some uppercase characters
-- followed by some '>'
closingTag = do
_ <- char '\n'
r <- between (string "</") (char '>') (many upper)
return r
答案 0 :(得分:4)
string
的类型为
string :: Stream s m Char => String -> ParsecT s u m String
(有关文档,请参阅here)
所以让String
回来正是应该发生的事情。
类型推断不会更改类型,它只会推断它们。 String
是具体类型,因此无法推断出Text
。
如果你需要在几个地方做的话,你可以做的是编写一个函数
text :: Stream s m Char => String -> ParsecT s u m Text
text = fmap pack . string
甚至
string' :: (IsString a, Stream s m Char) => String -> ParsecT s u m a
string' = fmap fromString . string
此外,在此示例中无关紧要,但您可能想要导入Text
限定条件,pack
等名称会在许多不同的模块中使用。
正如ØrjanJohansen正确指出的那样,string
实际上不是问题,many upper
是。同样的原则适用。
答案 1 :(得分:3)
此处获得[Char]
的原因是upper
解析Char
并many
将其转换为[Char]
。我会按照以下方式编写自己的组合器:
manyPacked = fmap pack . many
您可以使用类型级别的类型级编程来自动选择many
和manyPack
,具体取决于期望的返回类型,但我认为这不值得。 (它可能看起来有点像Scala的CanBuiltFrom)。