我正在解析一个复杂的格式,它变得非常重复。希望有人有一个更好的想法,大约是干燥的3倍。想知道根据字段的数据类型选择正确的原始解析器是否有一些魔力。
data Body = Body { raw :: ByteString }
| Far { cpuType :: !Word8
, stdfVer :: !Word8 }
| Prr { headNum :: !Word8
, siteNum :: !Word8
, partFlg :: !Word8
, numTest :: !Word16
, hardBin :: !Word16
, softBin :: !Word16
, xCoord :: !Word16
, yCoord :: !Word16
, testTime :: !Word32
, partID :: ByteString
, partTxt :: ByteString
, partFix :: ByteString }
deriving (Show)
getPrr :: Get Body
getPrr = do
headNum <- u1
siteNum <- u1
partFlg <- u1
numTest <- u2
hardBin <- u2
softBin <- u2
xCoord <- u2
yCoord <- u2
testTime <- u4
partID <- getVarLen
partTxt <- getVarLen
partFix <- getVarLen
return Prr {headNum = headNum
,siteNum = siteNum
,partFlg = partFlg
,numTest = numTest
,hardBin = hardBin
,softBin = softBin
,xCoord = xCoord
,yCoord = yCoord
,testTime = testTime
,partID = partID
,partTxt = partTxt
,partFix = partFix }
答案 0 :(得分:2)
使用Applicative
!
getPrr :: Get Body
getPrr = Prr <$> u1 <*> u1 <*> u1 <*> u2 <*> u2 <*> u2 <*> u2 <*> u2 <*> u4 <*> getVarLen <*> getVarLen <*> getVarLen
让我们看看它是如何工作的:
所以我们从:
开始Prr :: Word8 -> Word8 -> Word8 -> Word16 -> Word16 -> Word16 -> Word16 -> Word16 -> Word32 -> ByteString -> ByteString -> ByteString -> Body
u1 :: Get Word8
u2 :: Get Word16
u4 :: Get Word32
getVarLen :: Get ByteString
我们的运营商:
(<$>) :: Functor f => (a -> b) -> f a -> f b -- aka `fmap`
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
因此,我们逐一合并这些部分
Prr <$> u1
:: Get (Word8 -> Word8 -> Word16 -> Word16 -> Word16 -> Word16 -> Word16 -> Word32 -> ByteString -> ByteString -> ByteString -> Body)
Prr <$> u1 <*> u1
:: Get (Word8 -> Word16 -> Word16 -> Word16 -> Word16 -> Word16 -> Word32 -> ByteString -> ByteString -> ByteString -> Body)
Prr <$> u1 <*> u1 <*> u1
:: Get (Word16 -> Word16 -> Word16 -> Word16 -> Word16 -> Word32 -> ByteString -> ByteString -> ByteString -> Body)
Prr <$> u1 <*> u1 <*> u1 <*> u2
:: Get (Word16 -> Word16 -> Word16 -> Word16 -> Word32 -> ByteString -> ByteString -> ByteString -> Body)
Prr <$> u1 <*> u1 <*> u1 <*> u2 <*> u2
:: Get (Word16 -> Word16 -> Word16 -> Word32 -> ByteString -> ByteString -> ByteString -> Body)
Prr <$> u1 <*> u1 <*> u1 <*> u2 <*> u2 <*> u2
:: Get (Word16 -> Word16 -> Word32 -> ByteString -> ByteString -> ByteString -> Body)
Prr <$> u1 <*> u1 <*> u1 <*> u2 <*> u2 <*> u2 <*> u2
:: Get (Word16 -> Word32 -> ByteString -> ByteString -> ByteString -> Body)
Prr <$> u1 <*> u1 <*> u1 <*> u2 <*> u2 <*> u2 <*> u2 <*> u2
:: Get (Word32 -> ByteString -> ByteString -> ByteString -> Body)
Prr <$> u1 <*> u1 <*> u1 <*> u2 <*> u2 <*> u2 <*> u2 <*> u2 <*> u2
:: Get (ByteString -> ByteString -> ByteString -> Body)
Prr <$> u1 <*> u1 <*> u1 <*> u2 <*> u2 <*> u2 <*> u2 <*> u2 <*> u2 <*> getVarLen
:: Get (ByteString -> ByteString -> Body)
Prr <$> u1 <*> u1 <*> u1 <*> u2 <*> u2 <*> u2 <*> u2 <*> u2 <*> u2 <*> getVarLen <*> getVarLen
:: Get (ByteString -> Body)
Prr <$> u1 <*> u1 <*> u1 <*> u2 <*> u2 <*> u2 <*> u2 <*> u2 <*> u2 <*> getVarLen <*> getVarLen <*> getVarLen
:: Get Body
值得注意的是,所有Monad
都可以是Applicative
s(并且在未来版本的GHC中,将需要)。
如果Get
没有Applicative
个实例(which it does),我们可以
从Monad
实例中轻松制作一个:
instance Applicative Get where
pure = return
mf <*> ma = do
f <- mf
a <- ma
return $ f a