+
+ go2 ∷ Word32 → WordsData → bs → Int → New v Int32
+ → (# WordsData, bs, Int, New v Int32 #)
+ go2 0 w bs n v
+ = let ent = getEntropy n w
+ low = 0
+ high = getMedian0 ent
+ ent' = decMedian0 ent
+ w' = setEntropy ent' n w
+ in
+ go3 low high w' bs n v
+ go2 1 w bs n v
+ = let ent = getEntropy n w
+ low = getMedian0 ent
+ high = low + getMedian1 ent - 1
+ ent' = (incMedian0 ∘ decMedian1) ent
+ w' = setEntropy ent' n w
+ in
+ go3 low high w' bs n v
+ go2 2 w bs n v
+ = let ent = getEntropy n w
+ low = getMedian0 ent + getMedian1 ent
+ high = low + getMedian2 ent - 1
+ ent' = (incMedian0 ∘ incMedian1 ∘ decMedian2) ent
+ w' = setEntropy ent' n w
+ in
+ go3 low high w' bs n v
+ go2 onesCount w bs n v
+ = let ent = getEntropy n w
+ low = getMedian0 ent + getMedian1 ent + (onesCount-2) ⋅ getMedian2 ent
+ high = low + getMedian2 ent - 1
+ ent' = (incMedian0 ∘ incMedian1 ∘ incMedian2) ent
+ w' = setEntropy ent' n w
+ in
+ go3 low high w' bs n v
+
+ go3 ∷ Word32 → Word32 → WordsData → bs → Int → New v Int32
+ → (# WordsData, bs, Int, New v Int32 #)
+ go3 low high w bs n v
+ = let (# code, bs' #)
+ = readCode bs (high - low)
+ low' = low + code
+ a = if B.head bs' then
+ fromIntegral $ complement low'
+ else
+ fromIntegral low'
+ bs'' = B.tail bs'
+ v' = New.modify (\mv → MV.unsafeWrite mv n a) v
+ n' = n + 1
+ in
+ go0 w bs'' n' v'
+
+ getEntropy ∷ Int → WordsData → EntropyData
+ getEntropy n w
+ | isMono = fst $ wdEntropyData w
+ | n `testBit` 0 = fst $ wdEntropyData w
+ | otherwise = snd $ wdEntropyData w
+
+ setEntropy ∷ EntropyData → Int → WordsData → WordsData
+ setEntropy e n w
+ | isMono = w { wdEntropyData = (e, snd $ wdEntropyData w) }
+ | n `testBit` 0 = w { wdEntropyData = (e, snd $ wdEntropyData w) }
+ | otherwise = w { wdEntropyData = (fst $ wdEntropyData w, e) }