Question

I need to read some amount of bits from Get monad. Now my code looks like

readBits :: Int -> Int -> Get (Word32, Int)
readBits count state = ...

readValue :: Get (Word32, Word32)
readValue = do
   -- read fst bit count 
   (bits1, s0) <- readBits 5 0
   -- read bits1 bits as fst
   (fst, s1) <- readBits bits1 s0
   -- read snd bit count
   (bits2, s2) <- readBits 5 s1
   -- read bits2 bits as snd
   (snd, s3) <- readBits bits2 s2  
   -- flush incomplete byte
   when (s3 /= 0) $ skip 1
   return (fst, snd)

I want to wrap this into some kind of state monad, to have code like

readBits :: Int -> BitReader Word32
readBits count = ...

runBitReader :: BitReader a -> Get a

readValue :: Get (Word32, Word32) 
readValue = runBitReader $ do
      bits1 <- readBits 5
      fst <- readBits bits1
      bits2 <- readBits 5
      snd <- readBits bits2
      return (fst, snd)

What functions should I implement? How should they be implemented?

I have looked into Get and BitGet source code, but not fully understand what's going on.

Was it helpful?

Solution

This is the most typical usecase for Monad Transformers.

You have defined most of the structure correctly. To answer your questions

What functions should I implement? 
  • Well you first need to wrap Get monad into the StateT Transformer to get BitReader.
  • You need to implement proper definition for readBits using get to get the current state and put to save the state back.
  • You need to run your code wrapped in BitReader to get back the output in Get Monad. So you need to define runBitReader using runStateT.

To answer your next question.

How should they be implemented?

I have given the possible implementation. You still need to define some functions to make it work.

import Control.Monad.State 
import qualified Control.Monad.State as ST
import Data.Binary 

type BitReader = StateT Int Get

readBits' :: Int -> Int -> Get (Word32, Int)
readBits' = undefined   

readBits :: Int -> BitReader Word32
readBits n = do 
    s0 <- ST.get 
    (a,s1) <- lift $ readBits' n s0
    ST.put s1 
    return a


runBitReader :: BitReader a -> Get a
runBitReader w = do 
    (a,s) <- runStateT w 0
    return a

readValue = do
      fst <- readBits 5
      snd <- readBits 10
      return (fst, snd) 

I don't know how looking into code of Get was going to help you. You were looking in the wrong house. You need to read about State Monads and Monad Transformers.

You can read more about monad transformers here.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top