我尝试使用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
必须有更好的方法来实现像这样简单的事情。我错过了什么吗?
答案 0 :(得分:1)
您的代码段远非自包含(特别是导入和Packet
数据类型的定义缺失),但您似乎过于复杂。
首先,为一位数整数定义一个解析器。然后,使用后者作为两位整数解析器的构建块。之后,使用applicative运算符组合这两个解析器并为自定义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"