我试图用attoparsec从3个字符解析两个整数。一个示例输入可能看起来像这样:
341
…我想将其解析为:
Constructor 34 1
我有两个解决方案,但有点笨拙:
stdK :: P.Parser Packet
stdK = do
P.char '1'
qstr <- P.take 2
let q = rExt $ P.parseOnly P.decimal qstr
n <- P.decimal
return $ Std q n
stdK2 :: P.Parser Packet
stdK2 = do
P.char '1'
qn <- P.decimal
let q = div qn 10
let n = rem qn 10
return $ Std q n
一定有更好的方法来实现这么简单的事情。我错过什么了吗?
您的代码片段远不是自包含的(特别是,缺少导入和Packet
数据类型的定义),但是您似乎将事情复杂化了。
首先,定义一个一位数整数的解析器。然后,将后者用作两位数整数解析器的构建块。之后,使用应用操作符组合这两个解析器,并为自定义Packet
数据类型定义一个解析器。见下文.
注意,你不需要monad的全部功能;在这里,应用解析就足够了。
-- test_attoparsec.hs
{-# LANGUAGE OverloadedStrings #-}
import Control.Applicative ((<$>))
import Data.Attoparsec.Text
import Data.Char
data Packet = Std {-# UNPACK #-} !Int
{-# UNPACK #-} !Int
deriving (Show)
stdK :: Parser Packet
stdK = char '1' *> (Std <$> twoDigitInt <*> oneDigitInt)
twoDigitInt :: Parser Int
twoDigitInt = timesTenPlus <$> oneDigitInt <*> oneDigitInt
where
timesTenPlus x y = 10 * x + y
oneDigitInt :: Parser Int
oneDigitInt = digitToInt <$> digit
GHCi试验:
λ> :l test_attoparsec.hs
[1 of 1] Compiling Main ( test_attoparsec.hs, interpreted )
Ok, modules loaded: Main.
λ> :set -XOverloadedStrings
λ> parseOnly stdK "1341"
Right (Std 34 1)
λ> parseOnly stdK "212"
Left "1: Failed reading: satisfyWith"