2

我有以下,类型检查:

p_int = liftA read (many (char ' ') *> many1 digit <* many (char ' '))

现在,正如函数名所暗示的,我希望它给我一个 Int。但如果我这样做:

p_int = liftA read (many (char ' ') *> many1 digit <* many (char ' ')) :: Int

我收到这种类型的错误:

Couldn't match expected type `Int' with actual type `f0 b0'
In the return type of a call of `liftA'
In the expression:
    liftA read (many (char ' ') *> many1 digit <* many (char ' ')) ::
      Int
In an equation for `p_int':
    p_int
      = liftA read (many (char ' ') *> many1 digit <* many (char ' ')) ::
          Int

有没有一种更简单、更简洁的方法来解析可能有空格的整数?或者有办法解决这个问题?

最终,我希望这成为以下内容的一部分:

betaLine = string "BETA " *> p_int <*> p_int  <*> p_int <*>
           p_int <*> p_parallel <*> p_exposure <* eol

这是解析如下所示的行:

BETA  6 11 5 24 -1 oiiio

所以我最终可以调用一个需要这些值的 BetaPair 构造函数(一些作为 Int,一些作为其他类型,如 [Exposure] 和 Parallel)

(如果你好奇,这是一个文件格式的解析器,它代表蛋白质中的氢键 β 链对等。我无法控制文件格式!)

4

3 回答 3

8

如何让 Parsec 让我打电话read :: Int

第二个答案是“不要使用读取”。

使用read等同于重新解析您已经解析的数据 - 因此在 Parsec 解析器中使用它是一种代码味道。解析自然数足够无害,但read与 Parsec 具有不同的失败语义,并且它是针对 Haskell 的词法语法量身定制的,因此将其用于更复杂的数字格式是有问题的。

如果您不想麻烦地定义 aLanguageDef和使用 Parsec 的Token模块,这里是一个不使用 read 的自然数解析器:

-- | Needs @foldl'@ from Data.List and 
-- @digitToInt@ from Data.Char.
--
positiveNatural :: Stream s m Char => ParsecT s u m Int
positiveNatural = 
    foldl' (\a i -> a * 10 + digitToInt i) 0 <$> many1 digit
于 2012-05-23T19:45:25.243 回答
5

p_int是产生 的解析器Int,因此类型将是Parser Int或相似¹。

p_int = liftA read (many (char ' ') *> many1 digit <* many (char ' ')) :: Parser Int

或者,您可以键入read函数,(read :: String -> Int)以告诉编译器表达式具有哪种类型。

p_int = liftA (read :: String -> Int) (many (char ' ') *> many1 digit <* many (char ' ')) :: Int

至于更清洁的方式,请考虑替换many (char ' ')spaces.

¹ ParsecT x y z Int,例如。

于 2012-05-23T18:55:26.993 回答
1

你可能会发现

Text-Megaparsec-Lexer.integer :: MonadParsec s m Char => m Integer

做你想做的事。

vanilla parsec 库似乎缺少一些明显的解析器,这导致了“包含电池”的 parsec 衍生包的兴起。我想 parsec 维护者最终会得到更好的。

https://hackage.haskell.org/package/megaparsec-4.2.0/docs/Text-Megaparsec-Lexer.html

更新

或使用香草秒差:

Prelude Text.Parsec Text.Parsec.Language Text.Parsec.Token> parse ( integer . makeTokenParser $ haskellStyle ) "integer" "-1234"
Right (-1234)
于 2015-11-22T04:28:45.840 回答