我有以下类型检查:
p_int = liftA read (many (char ' ') *> many1 digit <* many (char ' '))
Run Code Online (Sandbox Code Playgroud)
现在,正如函数名称所暗示的那样,我希望它能给我一个Int.但如果我这样做:
p_int = liftA read (many (char ' ') *> many1 digit <* many (char ' ')) :: Int
Run Code Online (Sandbox Code Playgroud)
我收到这种类型的错误:
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
Run Code Online (Sandbox Code Playgroud)
是否有更简单,更清晰的方法来解析可能有空格的整数?或者解决这个问题的方法?
最终,我希望这成为以下内容的一部分:
betaLine = string "BETA " *> p_int <*> p_int <*> p_int <*>
p_int <*> p_parallel <*> p_exposure <* eol
Run Code Online (Sandbox Code Playgroud)
这是解析看起来像这样的行:
BETA 6 11 5 24 -1 oiiio
Run Code Online (Sandbox Code Playgroud)
所以我最终可以调用一个需要这些值的BetaPair构造函数(一些作为Int,一些像其他类型,如[Exposure]和Parallel)
(如果你很好奇,这是一个文件格式的解析器,它代表蛋白质中氢键合的β-链对.我无法控制文件格式!)
我怎么让Parsec让我打电话
read :: Int?
第二个答案是"不要使用阅读".
使用read等同于重新解析已经解析的数据 - 因此在Parsec解析器中使用它是代码气味.解析自然数是无害的,但是read对Parsec有不同的失败语义,并且它适合于Haskell的词法语法,因此将它用于更复杂的数字格式是有问题的.
如果你不想去定义LanguageDef和使用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
Run Code Online (Sandbox Code Playgroud)
p_int是一个产生一个的解析器Int,所以类型是Parser Int或类似的¹.
p_int = liftA read (many (char ' ') *> many1 digit <* many (char ' ')) :: Parser Int
Run Code Online (Sandbox Code Playgroud)
或者,您可以键入read函数,(read :: String -> Int)以告诉编译器表达式具有哪种类型.
p_int = liftA (read :: String -> Int) (many (char ' ') *> many1 digit <* many (char ' ')) :: Int
Run Code Online (Sandbox Code Playgroud)
而对于更清洁的方式,考虑更换many (char ' ')带spaces.
¹ ParsecT x y z Int,例如.
| 归档时间: |
|
| 查看次数: |
1424 次 |
| 最近记录: |