Я играл с простой двоичной кодировкой, и, похоже, по большей части она работала правильно, пока я не добавил монаду состояния. План состоял в том, чтобы использовать состояние для хранения таблицы поиска того, что я записал в байтовую строку до сих пор, а затем записать смещения к предыдущим экземплярам строк, а не дублировать их.
Я проверил и запустил все типы, но потом я заметил, что это только записывает последнюю инструкцию в цепочке. Я перешел на использование Control.Monad.State.Strict, но это не имело никакого значения, поэтому я подозреваю, что делаю фундаментальную ошибку где-то еще, но я не уверен, где именно - я урезал код до базовой функциональности. . Кроме того, есть ли более идиоматический способ сделать это?
{-# LANGUAGE OverloadedStrings #-}
import Control.Applicative
import qualified Control.Monad.State.Strict as S
import Data.Binary.Put
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BL
data SState = SState {
wsPosition :: Int
-- plus whatever else
}
initialState = SState 0
type StatePut = S.State SState Put
class StateBinary a where
sput :: a -> StatePut
incPos :: Int -> S.State SState ()
incPos amnt = do
(SState p) <- S.get
S.put $ SState (p + amnt)
writeSized :: Int -> (a -> Put) -> a -> StatePut
writeSized n f x = do
incPos n
return (f x)
writeInt32 :: Int -> StatePut
writeInt32 = writeSized 32 putWord32be . fromIntegral
writeBS :: BS.ByteString -> StatePut
writeBS b = writeSized (BS.length b) putByteString b
data SomeData = SomeData {
sdName :: BS.ByteString
, sdAge :: Int
, sdN :: Int
} deriving (Show, Eq)
instance StateBinary SomeData where
sput (SomeData nm a n) = do
writeBS nm
writeInt32 a
writeInt32 n
testData = SomeData "TestName" 30 100
runSPut :: StateBinary a => a -> BL.ByteString
runSPut a = runPut $ S.evalState (sput a) initialState
-- runSPut testData returns "\NUL\NUL\NULd"
writeSized
и откуда его следует импортировать? Этот код у меня не компилируется. - person bheklilr   schedule 02.11.2013