diff --git a/Setup.hs b/Setup.hs
deleted file mode 100644
--- a/Setup.hs
+++ /dev/null
@@ -1,2 +0,0 @@
-import Distribution.Simple
-main = defaultMain
diff --git a/library/PrimitiveExtras/Bitmap.hs b/library/PrimitiveExtras/Bitmap.hs
--- a/library/PrimitiveExtras/Bitmap.hs
+++ b/library/PrimitiveExtras/Bitmap.hs
@@ -1,31 +1,31 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
 module PrimitiveExtras.Bitmap
-(
-  Bitmap,
-  empty,
-  singleton,
-  insert,
-  invert,
-  indexList,
-  boolList,
-  pair,
-  populatedIndex,
-  isPopulated,
-  population,
-  null,
-  bits,
-  populatedIndicesList,
-  int,
-  allBitsList,
-  allBitsUnfoldl,
-  populatedBitsUnfoldl,
-  indicesAmongstPopulatedBitsUnfoldl,
-)
+  ( Bitmap (..),
+    empty,
+    singleton,
+    insert,
+    invert,
+    indexList,
+    boolList,
+    pair,
+    populatedIndex,
+    isPopulated,
+    population,
+    null,
+    bits,
+    populatedIndicesList,
+    int64,
+    allBitsList,
+    allBitsUnfoldl,
+    populatedBitsUnfoldl,
+    indicesAmongstPopulatedBitsUnfoldl,
+  )
 where
 
-import PrimitiveExtras.Prelude hiding (traverse_, insert, null, empty)
-import PrimitiveExtras.Types
 import qualified DeferredFolds.Unfoldl as Unfoldl
-
+import PrimitiveExtras.Prelude hiding (empty, insert, null, singleton, traverse_)
+import PrimitiveExtras.Types
 
 deriving instance Eq Bitmap
 
@@ -42,6 +42,7 @@
 allBitsList = [0 .. maxBit]
 
 -- * Constructors
+
 -------------------------
 
 {-# INLINE empty #-}
@@ -54,11 +55,11 @@
 
 {-# INLINE insert #-}
 insert :: Int -> Bitmap -> Bitmap
-insert i = Bitmap . (bit i .|.) . int
+insert i = Bitmap . (bit i .|.) . int64
 
 {-# INLINE invert #-}
 invert :: Int -> Bitmap -> Bitmap
-invert i = Bitmap . (bit i `xor`) . int
+invert i = Bitmap . (bit i `xor`) . int64
 
 {-# INLINE indexList #-}
 indexList :: [Int] -> Bitmap
@@ -66,13 +67,14 @@
 
 {-# INLINE boolList #-}
 boolList :: [Bool] -> Bitmap
-boolList = Bitmap . foldr (.|.) 0 . zipWith (\ index -> bool 0 (bit index)) allBitsList
+boolList = Bitmap . foldr (.|.) 0 . zipWith (\index -> bool 0 (bit index)) allBitsList
 
 {-# INLINE pair #-}
 pair :: Int -> Int -> Bitmap
 pair i1 i2 = Bitmap (bit i1 .|. bit i2)
 
 -- * Accessors
+
 -------------------------
 
 -- |
@@ -101,9 +103,9 @@
 populatedIndicesList :: Bitmap -> [Int]
 populatedIndicesList = enumFromTo 0 . pred . population
 
-{-# INLINE int #-}
-int :: Bitmap -> Int
-int (Bitmap int) = int
+{-# INLINE int64 #-}
+int64 :: Bitmap -> Int64
+int64 (Bitmap int) = int
 
 {-# NOINLINE allBitsUnfoldl #-}
 allBitsUnfoldl :: Unfoldl Int
diff --git a/library/PrimitiveExtras/By6Bits.hs b/library/PrimitiveExtras/By6Bits.hs
new file mode 100644
--- /dev/null
+++ b/library/PrimitiveExtras/By6Bits.hs
@@ -0,0 +1,197 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module PrimitiveExtras.By6Bits
+  ( By6Bits,
+    empty,
+    singleton,
+    maybeList,
+    pair,
+    insert,
+    replace,
+    adjust,
+    unset,
+    lookup,
+    focusAt,
+    toMaybeList,
+    toIndexedList,
+    elementsUnfoldl,
+    elementsUnfoldlM,
+    elementsListT,
+    onElementAtFocus,
+    null,
+  )
+where
+
+import qualified Focus
+import qualified PrimitiveExtras.Bitmap as Bitmap
+import PrimitiveExtras.Prelude hiding (empty, insert, lookup, null, singleton)
+import qualified PrimitiveExtras.Prelude as Prelude
+import qualified PrimitiveExtras.SmallArray as SmallArray
+import PrimitiveExtras.Types
+
+instance (Show a) => Show (By6Bits a) where
+  show = show . toMaybeList
+
+deriving instance (Eq a) => Eq (By6Bits a)
+
+instance Foldable By6Bits where
+  {-# INLINE foldr #-}
+  foldr step state = foldr step state . elementsUnfoldl
+  {-# INLINE foldl' #-}
+  foldl' step state = foldl' step state . elementsUnfoldl
+  {-# INLINE foldMap #-}
+  foldMap monoid = foldMap monoid . elementsUnfoldl
+
+{-# INLINE empty #-}
+empty :: By6Bits e
+empty = By6Bits Bitmap.empty Prelude.empty
+
+-- |
+-- An array with a single element at the specified index.
+{-# INLINE singleton #-}
+singleton :: Int -> e -> By6Bits e
+singleton i e =
+  let b = Bitmap.singleton i
+      a = runST $ newSmallArray 1 e >>= unsafeFreezeSmallArray
+   in By6Bits b a
+
+{-# INLINE pair #-}
+pair :: Int -> e -> Int -> e -> By6Bits e
+pair i1 e1 i2 e2 =
+  {-# SCC "pair" #-}
+  By6Bits bitmap array
+  where
+    bitmap = Bitmap.pair i1 i2
+    array = SmallArray.orderedPair i1 e1 i2 e2
+
+{-# INLINE maybeList #-}
+maybeList :: [Maybe e] -> By6Bits e
+maybeList list =
+  By6Bits (Bitmap.boolList (map isJust list)) (SmallArray.list (catMaybes list))
+
+-- |
+-- Insert an element value at the index.
+-- It's your obligation to ensure that the index is empty before the operation.
+{-# INLINE insert #-}
+insert :: Int -> e -> By6Bits e -> By6Bits e
+insert i e (By6Bits b a) =
+  {-# SCC "insert" #-}
+  let sparseIndex = Bitmap.populatedIndex i b
+   in By6Bits (Bitmap.insert i b) (SmallArray.insert sparseIndex e a)
+
+{-# INLINE replace #-}
+replace :: Int -> e -> By6Bits e -> By6Bits e
+replace i e (By6Bits b a) =
+  {-# SCC "replace" #-}
+  let sparseIndex = Bitmap.populatedIndex i b
+   in By6Bits b (SmallArray.set sparseIndex e a)
+
+{-# INLINE adjust #-}
+adjust :: (e -> e) -> Int -> By6Bits e -> By6Bits e
+adjust fn i (By6Bits b a) =
+  let sparseIndex = Bitmap.populatedIndex i b
+   in By6Bits
+        b
+        (SmallArray.unsafeAdjust fn sparseIndex a)
+
+-- |
+-- Remove an element.
+{-# INLINE unset #-}
+unset :: Int -> By6Bits e -> By6Bits e
+unset i (By6Bits (Bitmap b) a) =
+  {-# SCC "unset" #-}
+  let bitAtIndex = bit i
+      isPopulated = b .&. bitAtIndex /= 0
+   in if isPopulated
+        then
+          let populatedIndex = popCount (b .&. pred bitAtIndex)
+              updatedBitmap = xor b bitAtIndex
+              updatedArray = SmallArray.unset populatedIndex a
+           in By6Bits (Bitmap updatedBitmap) updatedArray
+        else By6Bits (Bitmap b) a
+
+-- |
+-- Lookup an item at the index.
+{-# INLINE lookup #-}
+lookup :: Int -> By6Bits e -> Maybe e
+lookup i (By6Bits b a) =
+  {-# SCC "lookup" #-}
+  if Bitmap.isPopulated i b
+    then Just (indexSmallArray a (Bitmap.populatedIndex i b))
+    else Nothing
+
+-- |
+-- Convert into a list representation.
+{-# INLINE toMaybeList #-}
+toMaybeList :: By6Bits e -> [Maybe e]
+toMaybeList ssa = do
+  i <- Bitmap.allBitsList
+  return (lookup i ssa)
+
+{-# INLINE toIndexedList #-}
+toIndexedList :: By6Bits e -> [(Int, e)]
+toIndexedList = catMaybes . zipWith (\i -> fmap (i,)) [0 ..] . toMaybeList
+
+{-# INLINE elementsUnfoldl #-}
+elementsUnfoldl :: By6Bits e -> Unfoldl e
+elementsUnfoldl (By6Bits _ array) = Unfoldl (\f z -> foldl' f z array)
+
+{-# INLINE elementsUnfoldlM #-}
+elementsUnfoldlM :: (Monad m) => By6Bits a -> UnfoldlM m a
+elementsUnfoldlM (By6Bits _ array) = SmallArray.elementsUnfoldlM array
+
+{-# INLINE elementsListT #-}
+elementsListT :: (Monad m) => By6Bits a -> ListT m a
+elementsListT (By6Bits _ array) = SmallArray.elementsListT array
+
+{-# INLINE onElementAtFocus #-}
+onElementAtFocus :: (Monad m) => Int -> Focus a m b -> Focus (By6Bits a) m b
+onElementAtFocus index (Focus concealA revealA) = Focus concealSsa revealSsa
+  where
+    concealSsa = fmap (fmap aChangeToSsaChange) concealA
+      where
+        aChangeToSsaChange = \case
+          Focus.Leave -> Focus.Leave
+          Focus.Set a -> Focus.Set (By6Bits (Bitmap.singleton index) (pure a))
+          Focus.Remove -> Focus.Leave
+    revealSsa (By6Bits indices array) =
+      fmap (fmap aChangeToSsaChange)
+        $ if Bitmap.isPopulated index indices
+          then do
+            a <- indexSmallArrayM array (Bitmap.populatedIndex index indices)
+            revealA a
+          else concealA
+      where
+        sparseIndex = Bitmap.populatedIndex index indices
+        aChangeToSsaChange = \case
+          Focus.Leave -> Focus.Leave
+          Focus.Set a ->
+            if Bitmap.isPopulated index indices
+              then
+                let newArray = SmallArray.set sparseIndex a array
+                 in Focus.Set (By6Bits indices newArray)
+              else
+                let newIndices = Bitmap.insert index indices
+                    newArray = SmallArray.insert sparseIndex a array
+                 in Focus.Set (By6Bits newIndices newArray)
+          Focus.Remove ->
+            let newIndices = Bitmap.invert index indices
+             in if Bitmap.null newIndices
+                  then Focus.Remove
+                  else
+                    let newArray = SmallArray.unset sparseIndex array
+                     in Focus.Set (By6Bits newIndices newArray)
+
+{-# INLINE focusAt #-}
+focusAt :: (Monad m) => Focus a m b -> Int -> By6Bits a -> m (b, By6Bits a)
+focusAt aFocus index = case onElementAtFocus index aFocus of
+  Focus conceal reveal -> \ssa -> do
+    (b, change) <- reveal ssa
+    return $ (b,) $ case change of
+      Focus.Leave -> ssa
+      Focus.Set newSsa -> newSsa
+      Focus.Remove -> empty
+
+{-# INLINE null #-}
+null :: By6Bits a -> Bool
+null (By6Bits bm _) = Bitmap.null bm
diff --git a/library/PrimitiveExtras/FoldMs.hs b/library/PrimitiveExtras/FoldMs.hs
--- a/library/PrimitiveExtras/FoldMs.hs
+++ b/library/PrimitiveExtras/FoldMs.hs
@@ -1,20 +1,20 @@
-module PrimitiveExtras.FoldMs
-where
+module PrimitiveExtras.FoldMs where
 
-import PrimitiveExtras.Prelude hiding (fold, foldM)
-import PrimitiveExtras.Types
 import Control.Foldl
-import qualified PrimitiveExtras.UnliftedArray as UA
-
+import PrimitiveExtras.Prelude hiding (fold, foldM)
 
-{-|
-Given a size of the array,
-construct a fold, which produces an array of elements.
--}
-primArray :: Prim a => Int {-^ Array size -} -> FoldM IO a (PrimArray a)
-primArray size = FoldM step init extract where
-  init = Product2 0 <$> newPrimArray size
-  step (Product2 index mutable) a = do
-    writePrimArray mutable index a
-    return (Product2 (succ index) mutable)
-  extract (Product2 _ mutable) = unsafeFreezePrimArray mutable
+-- |
+-- Given a size of the array,
+-- construct a fold, which produces an array of elements.
+primArray ::
+  (Prim a) =>
+  -- | Array size
+  Int ->
+  FoldM IO a (PrimArray a)
+primArray size = FoldM step init extract
+  where
+    init = Product2 0 <$> newPrimArray size
+    step (Product2 index mutable) a = do
+      writePrimArray mutable index a
+      return (Product2 (succ index) mutable)
+    extract (Product2 _ mutable) = unsafeFreezePrimArray mutable
diff --git a/library/PrimitiveExtras/Folds.hs b/library/PrimitiveExtras/Folds.hs
--- a/library/PrimitiveExtras/Folds.hs
+++ b/library/PrimitiveExtras/Folds.hs
@@ -1,45 +1,47 @@
 module PrimitiveExtras.Folds
-(
-  indexCounts,
-  unliftedArray,
-  primMultiArray,
-)
+  ( indexCounts,
+    unliftedArray,
+    primMultiArray,
+  )
 where
 
+import Control.Foldl
 import PrimitiveExtras.Prelude hiding (fold, foldM)
 import PrimitiveExtras.Types
-import Control.Foldl
 import qualified PrimitiveExtras.UnliftedArray as UA
 
-
 unsafeIO :: (state -> input -> IO state) -> IO state -> (state -> IO output) -> Fold input output
 unsafeIO stepInIO initInIO extractInIO =
   Fold
     (\ !state input -> unsafeDupablePerformIO (stepInIO state input))
     (unsafeDupablePerformIO initInIO)
-    (\ state -> let !output = unsafePerformIO (extractInIO state) in output)
-
-foldMInUnsafeDupableIO :: FoldM IO input output -> Fold input output
-foldMInUnsafeDupableIO (FoldM step init extract) = unsafeIO step init extract
+    (\state -> let !output = unsafePerformIO (extractInIO state) in output)
 
-{-|
-Given a size of the array,
-construct a fold, which produces an array of index counts.
--}
-indexCounts :: (Integral count, Prim count) => Int {-^ Array size -} -> Fold Int (PrimArray count)
-indexCounts size = unsafeIO step init extract where
-  init = unsafeThawPrimArray (replicatePrimArray size 0)
-  step mutable i = do
-    count <- readPrimArray mutable i
-    writePrimArray mutable i (succ count)
-    return mutable
-  extract = unsafeFreezePrimArray
+-- |
+-- Given a size of the array,
+-- construct a fold, which produces an array of index counts.
+indexCounts ::
+  (Integral count, Prim count) =>
+  -- | Array size
+  Int ->
+  Fold Int (PrimArray count)
+indexCounts size = unsafeIO step init extract
+  where
+    init = unsafeThawPrimArray (replicatePrimArray size 0)
+    step mutable i = do
+      count <- readPrimArray mutable i
+      writePrimArray mutable i (succ count)
+      return mutable
+    extract = unsafeFreezePrimArray
 
-{-|
-This function is partial in the sense that it expects the
-index vector of produced elements to be within the specified amount.
--}
-unliftedArray :: PrimUnlifted element => Int {-^ Size of the array -} -> Fold (Int, element) (UnliftedArray element)
+-- |
+-- This function is partial in the sense that it expects the
+-- index vector of produced elements to be within the specified amount.
+unliftedArray ::
+  (PrimUnlifted element) =>
+  -- | Size of the array
+  Int ->
+  Fold (Int, element) (UnliftedArray element)
 unliftedArray size =
   unsafeIO step init extract
   where
@@ -50,13 +52,12 @@
     extract =
       unsafeFreezeUnliftedArray
 
-{-|
-Having a priorly computed array of inner dimension sizes,
-e.g., using the 'indexCounts' fold,
-construct a fold over indexed elements into a multi-array of elements.
-
-Thus it allows to construct it in two passes over the indexed elements.
--}
+-- |
+-- Having a priorly computed array of inner dimension sizes,
+-- e.g., using the 'indexCounts' fold,
+-- construct a fold over indexed elements into a multi-array of elements.
+--
+-- Thus it allows to construct it in two passes over the indexed elements.
 primMultiArray :: forall size element. (Integral size, Prim size, Prim element) => PrimArray size -> Fold (Int, element) (PrimMultiArray element)
 primMultiArray sizeArray =
   unsafeIO step init extract
@@ -70,17 +71,17 @@
           unsafeThawPrimArray (replicatePrimArray outerLength 0)
         initMultiArray :: IO (UnliftedArray (MutablePrimArray RealWorld element))
         initMultiArray =
-          UA.generate outerLength $ \ index -> do
+          UA.generate outerLength $ \index -> do
             newPrimArray (fromIntegral (indexPrimArray sizeArray index))
     step (Product2 indexArray multiArray) (outerIndex, element) = do
-      innerArray <- indexUnliftedArrayM multiArray outerIndex
+      let innerArray = indexUnliftedArray multiArray outerIndex
       innerIndex <- readPrimArray indexArray outerIndex
       writePrimArray indexArray outerIndex (succ innerIndex)
       writePrimArray innerArray (fromIntegral innerIndex) element
       return (Product2 indexArray multiArray)
     extract (Product2 _ multiArray) = do
       copied <- unsafeNewUnliftedArray outerLength
-      forMFromZero_ outerLength $ \ outerIndex -> do
+      forMFromZero_ outerLength $ \outerIndex -> do
         let mutableInnerArray = indexUnliftedArray multiArray outerIndex
         frozenInnerArray <- unsafeFreezePrimArray mutableInnerArray
         writeUnliftedArray copied outerIndex frozenInnerArray
diff --git a/library/PrimitiveExtras/Prelude.hs b/library/PrimitiveExtras/Prelude.hs
--- a/library/PrimitiveExtras/Prelude.hs
+++ b/library/PrimitiveExtras/Prelude.hs
@@ -1,23 +1,22 @@
 module PrimitiveExtras.Prelude
-(
-  module Exports,
-  Product2(..),
-  modifyTVar',
-  forMToZero_,
-  forMFromZero_,
-)
+  ( module Exports,
+    Product2 (..),
+    modifyTVar',
+    forMToZero_,
+    forMFromZero_,
+  )
 where
 
--- base
--------------------------
 import Control.Applicative as Exports
 import Control.Arrow as Exports
 import Control.Category as Exports
 import Control.Concurrent as Exports
 import Control.Exception as Exports
-import Control.Monad as Exports hiding (mapM_, sequence_, forM_, msum, mapM, sequence, forM)
-import Control.Monad.IO.Class as Exports
+import Control.Foldl as Exports (Fold (..), FoldM (..))
+import Control.Monad as Exports hiding (forM, forM_, mapM, mapM_, msum, sequence, sequence_)
 import Control.Monad.Fix as Exports hiding (fix)
+import Control.Monad.IO.Class as Exports
+import Control.Monad.Primitive as Exports
 import Control.Monad.ST as Exports
 import Data.Bits as Exports
 import Data.Bool as Exports
@@ -30,15 +29,21 @@
 import Data.Fixed as Exports
 import Data.Foldable as Exports
 import Data.Function as Exports hiding (id, (.))
-import Data.Functor as Exports
+import Data.Functor as Exports hiding (unzip)
 import Data.Functor.Identity as Exports
-import Data.Int as Exports
 import Data.IORef as Exports
+import Data.Int as Exports
 import Data.Ix as Exports
-import Data.List as Exports hiding (sortOn, isSubsequenceOf, uncons, concat, foldr, foldl1, maximum, minimum, product, sum, all, and, any, concatMap, elem, foldl, foldr1, notElem, or, find, maximumBy, minimumBy, mapAccumL, mapAccumR, foldl')
+import Data.List as Exports hiding (all, and, any, concat, concatMap, elem, find, foldl, foldl', foldl1, foldr, foldr1, isSubsequenceOf, mapAccumL, mapAccumR, maximum, maximumBy, minimum, minimumBy, notElem, or, product, sortOn, sum, uncons)
 import Data.Maybe as Exports
-import Data.Monoid as Exports hiding (Last(..), First(..))
+import Data.Monoid as Exports hiding (First (..), Last (..))
 import Data.Ord as Exports
+import Data.Primitive as Exports
+import Data.Primitive.Unlifted.Array as Exports
+import Data.Primitive.Unlifted.Class as Exports
+import Data.Profunctor.Choice as Exports
+import Data.Profunctor.Strong as Exports
+import Data.Profunctor.Unsafe as Exports
 import Data.Proxy as Exports
 import Data.Ratio as Exports
 import Data.STRef as Exports
@@ -49,16 +54,19 @@
 import Data.Version as Exports
 import Data.Word as Exports
 import Debug.Trace as Exports
+import DeferredFolds.Unfoldl as Exports (Unfoldl (..))
+import DeferredFolds.UnfoldlM as Exports (UnfoldlM (..))
+import Focus as Exports (Focus (..))
 import Foreign.ForeignPtr as Exports
 import Foreign.Ptr as Exports
 import Foreign.StablePtr as Exports
-import Foreign.Storable as Exports hiding (sizeOf, alignment)
-import GHC.Conc as Exports hiding (withMVar, threadWaitWriteSTM, threadWaitWrite, threadWaitReadSTM, threadWaitRead)
-import GHC.Exts as Exports (lazy, inline, sortWith, groupWith)
+import Foreign.Storable as Exports hiding (alignment, sizeOf)
+import GHC.Conc as Exports hiding (threadWaitRead, threadWaitReadSTM, threadWaitWrite, threadWaitWriteSTM, withMVar)
+import GHC.Exts as Exports (groupWith, inline, lazy, sortWith)
 import GHC.Generics as Exports (Generic)
 import GHC.IO.Exception as Exports
+import ListT as Exports (ListT (..))
 import Numeric as Exports
-import Prelude as Exports hiding (concat, foldr, mapM_, sequence_, foldl1, maximum, minimum, product, sum, all, and, any, concatMap, elem, foldl, foldr1, notElem, or, mapM, sequence, id, (.))
 import System.Environment as Exports
 import System.Exit as Exports
 import System.IO as Exports
@@ -67,55 +75,25 @@
 import System.Mem as Exports
 import System.Mem.StableName as Exports
 import System.Timeout as Exports
-import Text.ParserCombinators.ReadP as Exports (ReadP, ReadS, readP_to_S, readS_to_P)
-import Text.ParserCombinators.ReadPrec as Exports (ReadPrec, readPrec_to_P, readP_to_Prec, readPrec_to_S, readS_to_Prec)
-import Text.Printf as Exports (printf, hPrintf)
-import Text.Read as Exports (Read(..), readMaybe, readEither)
+import Text.Printf as Exports (hPrintf, printf)
+import Text.Read as Exports (Read (..), readEither, readMaybe)
 import Unsafe.Coerce as Exports
-
--- profunctors
--------------------------
-import Data.Profunctor.Unsafe as Exports
-import Data.Profunctor.Choice as Exports
-import Data.Profunctor.Strong as Exports
-
--- deferred-folds
--------------------------
-import DeferredFolds.Unfoldl as Exports (Unfoldl(..))
-import DeferredFolds.UnfoldlM as Exports (UnfoldlM(..))
-
--- foldl
--------------------------
-import Control.Foldl as Exports (Fold(..), FoldM(..))
-
--- primitive
--------------------------
-import Data.Primitive as Exports
-import Control.Monad.Primitive as Exports
-
--- focus
--------------------------
-import Focus as Exports (Focus(..))
-
--- list-t
--------------------------
-import ListT as Exports (ListT(..))
-
+import Prelude as Exports hiding (all, and, any, concat, concatMap, elem, foldl, foldl1, foldr, foldr1, id, mapM, mapM_, maximum, minimum, notElem, or, product, sequence, sequence_, sum, (.))
 
 data Product2 a b = Product2 !a !b
 
 {-# INLINE modifyTVar' #-}
 modifyTVar' :: TVar a -> (a -> a) -> STM ()
 modifyTVar' var f = do
-    x <- readTVar var
-    writeTVar var $! f x
+  x <- readTVar var
+  writeTVar var $! f x
 
 {-# INLINE forMToZero_ #-}
-forMToZero_ :: Applicative m => Int -> (Int -> m a) -> m ()
+forMToZero_ :: (Applicative m) => Int -> (Int -> m a) -> m ()
 forMToZero_ !startN f =
   ($ pred startN) $ fix $ \loop !n -> if n >= 0 then f n *> loop (pred n) else pure ()
 
 {-# INLINE forMFromZero_ #-}
-forMFromZero_ :: Applicative m => Int -> (Int -> m a) -> m ()
+forMFromZero_ :: (Applicative m) => Int -> (Int -> m a) -> m ()
 forMFromZero_ !endN f =
   ($ 0) $ fix $ \loop !n -> if n < endN then f n *> loop (succ n) else pure ()
diff --git a/library/PrimitiveExtras/PrimArray.hs b/library/PrimitiveExtras/PrimArray.hs
--- a/library/PrimitiveExtras/PrimArray.hs
+++ b/library/PrimitiveExtras/PrimArray.hs
@@ -1,92 +1,96 @@
-module PrimitiveExtras.PrimArray
-where
+{-# OPTIONS_GHC -Wno-redundant-constraints #-}
 
-import PrimitiveExtras.Prelude hiding (replicateM, traverse_)
-import PrimitiveExtras.Types
+module PrimitiveExtras.PrimArray where
+
+import qualified Data.ByteString.Short.Internal as ShortByteString
 import qualified Data.Serialize as Cereal
-import qualified Data.Vector.Unboxed as UnboxedVector
 import qualified Data.Vector.Primitive as PrimitiveVector
-import qualified PrimitiveExtras.Folds as Folds
+import qualified Data.Vector.Unboxed as UnboxedVector
 import qualified PrimitiveExtras.FoldMs as FoldMs
-import qualified Data.ByteString.Short.Internal as ShortByteString
-
+import qualified PrimitiveExtras.Folds as Folds
+import PrimitiveExtras.Prelude hiding (replicateM, traverse_)
 
-{-|
-Construct from a primitive vector.
-In case the vector is not a slice, it is an /O(1)/ op.
--}
-primitiveVector :: Prim a => PrimitiveVector.Vector a -> PrimArray a
-primitiveVector (PrimitiveVector.Vector offset length (ByteArray unliftedByteArray)) = let
-  primArray = PrimArray unliftedByteArray
-  in if offset == 0 && length == sizeofPrimArray primArray
-    then primArray
-    else runST $ do
-      ma <- newPrimArray length
-      copyPrimArray ma 0 primArray offset length
-      unsafeFreezePrimArray ma
+-- |
+-- Construct from a primitive vector.
+-- In case the vector is not a slice, it is an /O(1)/ op.
+primitiveVector :: (Prim a) => PrimitiveVector.Vector a -> PrimArray a
+primitiveVector (PrimitiveVector.Vector offset length (ByteArray unliftedByteArray)) =
+  let primArray = PrimArray unliftedByteArray
+   in if offset == 0 && length == sizeofPrimArray primArray
+        then primArray
+        else runST $ do
+          ma <- newPrimArray length
+          copyPrimArray ma 0 primArray offset length
+          unsafeFreezePrimArray ma
 
-oneHot :: Prim a => Int {-^ Size -} -> Int {-^ Index -} -> a -> PrimArray a
+oneHot ::
+  (Prim a) =>
+  -- | Size
+  Int ->
+  -- | Index
+  Int ->
+  a ->
+  PrimArray a
 oneHot size index value =
   runST $ do
     marr <- newPrimArray size
     writePrimArray marr index value
     unsafeFreezePrimArray marr
 
-generate :: Prim a => Int -> (Int -> IO a) -> IO (PrimArray a)
+generate :: (Prim a) => Int -> (Int -> IO a) -> IO (PrimArray a)
 generate size elementIO =
   do
     array <- newPrimArray size
-    let
-      loop index =
-        if index < size
-          then do
-            element <- elementIO index
-            writePrimArray array index element
-            loop (succ index)
-          else unsafeFreezePrimArray array
-      in loop 0
+    let loop index =
+          if index < size
+            then do
+              element <- elementIO index
+              writePrimArray array index element
+              loop (succ index)
+            else unsafeFreezePrimArray array
+     in loop 0
 
-replicate :: Prim a => Int -> IO a -> IO (PrimArray a)
+replicate :: (Prim a) => Int -> IO a -> IO (PrimArray a)
 replicate size elementIO =
   do
     array <- newPrimArray size
-    let
-      loop index =
-        if index < size
-          then do
-            element <- elementIO
-            writePrimArray array index element
-            loop (succ index)
-          else unsafeFreezePrimArray array
-      in loop 0
+    let loop index =
+          if index < size
+            then do
+              element <- elementIO
+              writePrimArray array index element
+              loop (succ index)
+            else unsafeFreezePrimArray array
+     in loop 0
 
-{-| Please notice that this function is highly untested -}
+-- | Please notice that this function is highly untested
 replicateM :: (Monad m, Prim element) => Int -> m element -> m (PrimArray element)
 replicateM size elementM =
   do
     !mutable <- return (unsafeDupablePerformIO (newPrimArray size))
-    let 
-      iterate index =
-        if index < size
-          then do
-            element <- elementM
-            let !() = unsafeDupablePerformIO (writePrimArray mutable index element)
-            iterate (succ index)
-          else return (unsafePerformIO (unsafeFreezePrimArray mutable))
-      in iterate 0
+    let iterate index =
+          if index < size
+            then do
+              element <- elementM
+              let !() = unsafeDupablePerformIO (writePrimArray mutable index element)
+              iterate (succ index)
+            else return (unsafePerformIO (unsafeFreezePrimArray mutable))
+     in iterate 0
 
+traverse_ :: (Applicative f, Prim a) => (a -> f b) -> PrimArray a -> f ()
 traverse_ = traversePrimArray_
 
-traverseWithIndexInRange_ :: Prim a => PrimArray a -> Int -> Int -> (Int -> a -> IO ()) -> IO ()
+traverseWithIndexInRange_ :: (Prim a) => PrimArray a -> Int -> Int -> (Int -> a -> IO ()) -> IO ()
 traverseWithIndexInRange_ primArray from to action =
-  let iterate index = if index < to
-        then do
-          action index $! indexPrimArray primArray index
-          iterate (succ index)
-        else return ()
-      in iterate from
+  let iterate index =
+        if index < to
+          then do
+            action index $! indexPrimArray primArray index
+            iterate (succ index)
+          else return ()
+   in iterate from
 
-toElementsUnfoldl :: Prim prim => PrimArray prim -> Unfoldl prim
+toElementsUnfoldl :: (Prim prim) => PrimArray prim -> Unfoldl prim
 toElementsUnfoldl ba = Unfoldl $ \f z -> foldlPrimArray' f z ba
 
 toElementsUnfoldlM :: (Monad m, Prim prim) => PrimArray prim -> UnfoldlM m prim
@@ -96,51 +100,57 @@
 toByteArray (PrimArray unliftedByteArray) =
   ByteArray unliftedByteArray
 
-toPrimitiveVector :: Prim a => PrimArray a -> PrimitiveVector.Vector a
+toPrimitiveVector :: (Prim a) => PrimArray a -> PrimitiveVector.Vector a
 toPrimitiveVector primArray =
   PrimitiveVector.Vector 0 (sizeofPrimArray primArray) (toByteArray primArray)
 
-toUnboxedVector :: Prim a => PrimArray a -> UnboxedVector.Vector a
+toUnboxedVector :: (Prim a) => PrimArray a -> UnboxedVector.Vector a
 toUnboxedVector primArray =
   unsafeCoerce (toPrimitiveVector primArray)
 
-cerealGet :: Prim element => Cereal.Get Int -> Cereal.Get element -> Cereal.Get (PrimArray element)
+cerealGet :: (Prim element) => Cereal.Get Int -> Cereal.Get element -> Cereal.Get (PrimArray element)
 cerealGet int element =
   do
     size <- int
     replicateM size element
 
-cerealGetAsInMemory :: Prim element => Cereal.Get Int -> Cereal.Get (PrimArray element)
+cerealGetAsInMemory :: (Prim element) => Cereal.Get Int -> Cereal.Get (PrimArray element)
 cerealGetAsInMemory int =
   do
     size <- int
     ShortByteString.SBS ba <- Cereal.getShortByteString size
     return (PrimArray ba)
 
-cerealPut :: Prim element => Cereal.Putter Int -> Cereal.Putter element -> Cereal.Putter (PrimArray element)
+cerealPut :: (Prim element) => Cereal.Putter Int -> Cereal.Putter element -> Cereal.Putter (PrimArray element)
 cerealPut int element primArrayValue =
   size <> elements
   where
     size = int (sizeofPrimArray primArrayValue)
     elements = traverse_ element primArrayValue
 
-cerealPutAsInMemory :: Prim element => Cereal.Putter Int -> Cereal.Putter (PrimArray element)
+cerealPutAsInMemory :: (Prim element) => Cereal.Putter Int -> Cereal.Putter (PrimArray element)
 cerealPutAsInMemory int primArrayValue@(PrimArray ba) =
   size <> elements
   where
     size = int (sizeofByteArray (ByteArray ba))
     elements = Cereal.putShortByteString (ShortByteString.SBS ba)
 
-{-|
-Given a size of the array,
-construct a fold, which produces an array of index counts.
--}
-indexCountsFold :: (Integral count, Prim count) => Int {-^ Array size -} -> Fold Int (PrimArray count)
+-- |
+-- Given a size of the array,
+-- construct a fold, which produces an array of index counts.
+indexCountsFold ::
+  (Integral count, Prim count) =>
+  -- | Array size
+  Int ->
+  Fold Int (PrimArray count)
 indexCountsFold = Folds.indexCounts
 
-{-|
-Given a size of the array,
-construct a fold, which produces an array of elements.
--}
-elementsFoldM :: Prim a => Int {-^ Array size -} -> FoldM IO a (PrimArray a)
+-- |
+-- Given a size of the array,
+-- construct a fold, which produces an array of elements.
+elementsFoldM ::
+  (Prim a) =>
+  -- | Array size
+  Int ->
+  FoldM IO a (PrimArray a)
 elementsFoldM = FoldMs.primArray
diff --git a/library/PrimitiveExtras/PrimMultiArray.hs b/library/PrimitiveExtras/PrimMultiArray.hs
--- a/library/PrimitiveExtras/PrimMultiArray.hs
+++ b/library/PrimitiveExtras/PrimMultiArray.hs
@@ -1,45 +1,43 @@
+{-# OPTIONS_GHC -Wno-redundant-constraints -Wno-orphans #-}
+
 module PrimitiveExtras.PrimMultiArray
-(
-  PrimMultiArray,
-  create,
-  replicateM,
-  outerLength,
-  toAssocsUnfoldl,
-  toIndicesUnfoldl,
-  toUnfoldlAt,
-  toAssocsUnfoldlM,
-  toIndicesUnfoldlM,
-  toUnfoldlAtM,
-  cerealGet,
-  cerealGetAsInMemory,
-  cerealPut,
-  cerealPutAsInMemory,
-  fold,
-)
+  ( PrimMultiArray,
+    create,
+    replicateM,
+    outerLength,
+    toAssocsUnfoldl,
+    toIndicesUnfoldl,
+    toUnfoldlAt,
+    toAssocsUnfoldlM,
+    toIndicesUnfoldlM,
+    toUnfoldlAtM,
+    cerealGet,
+    cerealGetAsInMemory,
+    cerealPut,
+    cerealPutAsInMemory,
+    fold,
+  )
 where
 
-import PrimitiveExtras.Prelude hiding (replicateM, fold)
-import PrimitiveExtras.Types
+import qualified Data.Serialize as Cereal
 import qualified DeferredFolds.Unfoldl as Unfoldl
 import qualified DeferredFolds.UnfoldlM as UnfoldlM
-import qualified PrimitiveExtras.UnliftedArray as UnliftedArray
-import qualified PrimitiveExtras.PrimArray as PrimArray
 import qualified PrimitiveExtras.Folds as Folds
-import qualified Data.Serialize as Cereal
-
+import PrimitiveExtras.Prelude hiding (fold, replicateM)
+import qualified PrimitiveExtras.PrimArray as PrimArray
+import PrimitiveExtras.Types
+import qualified PrimitiveExtras.UnliftedArray as UnliftedArray
 
 deriving instance (Eq a, Prim a) => Eq (PrimMultiArray a)
 
-deriving instance (Ord a, Prim a) => Ord (PrimMultiArray a)
-
 instance (Show a, Prim a) => Show (PrimMultiArray a) where
   show (PrimMultiArray outerArray) =
-    unliftedArrayToList outerArray &
-    map primArrayToList &
-    show
+    unliftedArrayToList outerArray
+      & map primArrayToList
+      & show
 
-{-| Given a size of the outer array and a function, which executes a fold over indexed elements in a monad,
-constructs a prim multi-array -}
+-- | Given a size of the outer array and a function, which executes a fold over indexed elements in a monad,
+-- constructs a prim multi-array
 create :: (Monad m, Prim element) => Int -> (forall x. Fold (Int, element) x -> m x) -> m (PrimMultiArray element)
 create outerArraySize runFold =
   do
@@ -50,27 +48,26 @@
 replicateM size elementM =
   do
     !mutable <- return (unsafeDupablePerformIO (unsafeNewUnliftedArray size))
-    let 
-      iterate index =
-        if index < size
-          then do
-            element <- elementM
-            let !() = unsafeDupablePerformIO (writeUnliftedArray mutable index element)
-            iterate (succ index)
-          else return (PrimMultiArray (unsafePerformIO (unsafeFreezeUnliftedArray mutable)))
-      in iterate 0
+    let iterate index =
+          if index < size
+            then do
+              element <- elementM
+              let !() = unsafeDupablePerformIO (writeUnliftedArray mutable index element)
+              iterate (succ index)
+            else return (PrimMultiArray (unsafePerformIO (unsafeFreezeUnliftedArray mutable)))
+     in iterate 0
 
-{-| Get length of the outer dimension of a primitive multi array -}
+-- | Get length of the outer dimension of a primitive multi array
 outerLength :: PrimMultiArray a -> Int
 outerLength (PrimMultiArray outerDimension) = sizeofUnliftedArray outerDimension
 
-toAssocsUnfoldl :: Prim a => PrimMultiArray a -> Unfoldl (Int, a)
+toAssocsUnfoldl :: (Prim a) => PrimMultiArray a -> Unfoldl (Int, a)
 toAssocsUnfoldl = Unfoldl.unfoldlM . toAssocsUnfoldlM
 
 toIndicesUnfoldl :: PrimMultiArray a -> Unfoldl Int
 toIndicesUnfoldl (PrimMultiArray ua) = Unfoldl.intsInRange 0 (pred (sizeofUnliftedArray ua))
 
-toUnfoldlAt :: Prim prim => PrimMultiArray prim -> Int -> Unfoldl prim
+toUnfoldlAt :: (Prim prim) => PrimMultiArray prim -> Int -> Unfoldl prim
 toUnfoldlAt (PrimMultiArray ua) index = UnliftedArray.at ua index empty PrimArray.toElementsUnfoldl
 
 toAssocsUnfoldlM :: (Monad m, Prim a) => PrimMultiArray a -> UnfoldlM m (Int, a)
@@ -80,44 +77,43 @@
     element <- toUnfoldlAtM pma index
     return (index, element)
 
-toIndicesUnfoldlM :: Monad m => PrimMultiArray a -> UnfoldlM m Int
+toIndicesUnfoldlM :: (Monad m) => PrimMultiArray a -> UnfoldlM m Int
 toIndicesUnfoldlM (PrimMultiArray ua) = UnfoldlM.intsInRange 0 (pred (sizeofUnliftedArray ua))
 
 toUnfoldlAtM :: (Monad m, Prim prim) => PrimMultiArray prim -> Int -> UnfoldlM m prim
 toUnfoldlAtM (PrimMultiArray ua) index = UnliftedArray.at ua index empty PrimArray.toElementsUnfoldlM
 
-cerealGet :: Prim element => Cereal.Get Int -> Cereal.Get element -> Cereal.Get (PrimMultiArray element)
+cerealGet :: (Prim element) => Cereal.Get Int -> Cereal.Get element -> Cereal.Get (PrimMultiArray element)
 cerealGet int element =
   do
     size <- int
     replicateM size (PrimArray.cerealGet int element)
 
-cerealGetAsInMemory :: Prim element => Cereal.Get Int -> Cereal.Get (PrimMultiArray element)
+cerealGetAsInMemory :: (Prim element) => Cereal.Get Int -> Cereal.Get (PrimMultiArray element)
 cerealGetAsInMemory int =
   do
     size <- int
     replicateM size (PrimArray.cerealGetAsInMemory int)
 
-cerealPut :: Prim element => Cereal.Putter Int -> Cereal.Putter element -> Cereal.Putter (PrimMultiArray element)
+cerealPut :: (Prim element) => Cereal.Putter Int -> Cereal.Putter element -> Cereal.Putter (PrimMultiArray element)
 cerealPut int element (PrimMultiArray outerArrayValue) =
   size <> innerArrays
   where
     size = int (sizeofUnliftedArray outerArrayValue)
     innerArrays = UnliftedArray.traverse_ (PrimArray.cerealPut int element) outerArrayValue
 
-cerealPutAsInMemory :: Prim element => Cereal.Putter Int -> Cereal.Putter (PrimMultiArray element)
+cerealPutAsInMemory :: (Prim element) => Cereal.Putter Int -> Cereal.Putter (PrimMultiArray element)
 cerealPutAsInMemory int (PrimMultiArray outerArrayValue) =
   size <> innerArrays
   where
     size = int (sizeofUnliftedArray outerArrayValue)
     innerArrays = UnliftedArray.traverse_ (PrimArray.cerealPutAsInMemory int) outerArrayValue
 
-{-|
-Having a priorly computed array of inner dimension sizes,
-e.g., using the 'PrimitiveExtras.PrimArray.indexCountsFold',
-construct a fold over indexed elements into a multi-array of elements.
-
-Thus it allows to construct it in two passes over the indexed elements.
--}
+-- |
+-- Having a priorly computed array of inner dimension sizes,
+-- e.g., using the 'PrimitiveExtras.PrimArray.indexCountsFold',
+-- construct a fold over indexed elements into a multi-array of elements.
+--
+-- Thus it allows to construct it in two passes over the indexed elements.
 fold :: (Integral size, Prim size, Prim element) => PrimArray size -> Fold (Int, element) (PrimMultiArray element)
 fold = Folds.primMultiArray
diff --git a/library/PrimitiveExtras/SmallArray.hs b/library/PrimitiveExtras/SmallArray.hs
--- a/library/PrimitiveExtras/SmallArray.hs
+++ b/library/PrimitiveExtras/SmallArray.hs
@@ -1,31 +1,27 @@
-module PrimitiveExtras.SmallArray
-where
+module PrimitiveExtras.SmallArray where
 
-import PrimitiveExtras.Prelude
-import PrimitiveExtras.Types
-import GHC.Exts hiding (toList)
 import qualified Focus
+import GHC.Exts hiding (toList)
 import qualified ListT
-
+import PrimitiveExtras.Prelude
 
-{-| A workaround for the weird forcing of 'undefined' values int 'newSmallArray' -}
+-- | A workaround for the weird forcing of 'undefined' values int 'newSmallArray'
 {-# INLINE newEmptySmallArray #-}
-newEmptySmallArray :: PrimMonad m => Int -> m (SmallMutableArray (PrimState m) a)
+newEmptySmallArray :: (PrimMonad m) => Int -> m (SmallMutableArray (PrimState m) a)
 newEmptySmallArray size = newSmallArray size (unsafeCoerce 0)
 
 {-# INLINE list #-}
 list :: [a] -> SmallArray a
 list list =
-  let
-    !size = length list
-    in runSmallArray $ do
-      m <- newEmptySmallArray size
-      let populate index list = case list of
-            element : list -> do
-              writeSmallArray m index element
-              populate (succ index) list
-            [] -> return m
-          in populate 0 list
+  let !size = length list
+   in runSmallArray $ do
+        m <- newEmptySmallArray size
+        let populate index list = case list of
+              element : list -> do
+                writeSmallArray m index element
+                populate (succ index) list
+              [] -> return m
+         in populate 0 list
 
 -- |
 -- Remove an element.
@@ -37,7 +33,7 @@
       !newSize = pred size
       !newIndex = succ index
       !amountOfFollowingElements = size - newIndex
-      in runSmallArray $ do
+   in runSmallArray $ do
         newMa <- newSmallArray newSize undefined
         copySmallArray newMa 0 array 0 index
         copySmallArray newMa index array newIndex amountOfFollowingElements
@@ -46,131 +42,181 @@
 {-# INLINE set #-}
 set :: Int -> a -> SmallArray a -> SmallArray a
 set index a array =
-  {-# SCC "set" #-} 
-  let
-    !size = sizeofSmallArray array
-    in runSmallArray $ do
-      newMa <- newSmallArray size undefined
-      copySmallArray newMa 0 array 0 size
-      writeSmallArray newMa index a
-      return newMa
+  {-# SCC "set" #-}
+  let size = sizeofSmallArray array
+   in runST $ do
+        m <- thawSmallArray array 0 size
+        writeSmallArray m index a
+        unsafeFreezeSmallArray m
 
 {-# INLINE insert #-}
 insert :: Int -> a -> SmallArray a -> SmallArray a
 insert index a array =
-  {-# SCC "insert" #-} 
-  let
-    !size = sizeofSmallArray array
-    !newSize = succ size
-    !nextIndex = succ index
-    !amountOfFollowingElements = size - index
-    in runSmallArray $ do
-      newMa <- newSmallArray newSize a
-      copySmallArray newMa 0 array 0 index
-      copySmallArray newMa nextIndex array index amountOfFollowingElements
-      return newMa
+  {-# SCC "insert" #-}
+  let !size = sizeofSmallArray array
+      !newSize = succ size
+      !nextIndex = succ index
+      !amountOfFollowingElements = size - index
+   in runSmallArray $ do
+        newMa <- newSmallArray newSize a
+        copySmallArray newMa 0 array 0 index
+        copySmallArray newMa nextIndex array index amountOfFollowingElements
+        return newMa
 
+{-# INLINE adjust #-}
+adjust :: (a -> a) -> Int -> SmallArray a -> SmallArray a
+adjust fn index array =
+  let size = sizeofSmallArray array
+   in if size > index && index >= 0
+        then unsafeAdjustWithSize fn index size array
+        else array
+
+{-# INLINE unsafeAdjust #-}
+unsafeAdjust :: (a -> a) -> Int -> SmallArray a -> SmallArray a
+unsafeAdjust fn index array =
+  unsafeAdjustWithSize fn index (sizeofSmallArray array) array
+
+{-# INLINE unsafeAdjustWithSize #-}
+unsafeAdjustWithSize :: (a -> a) -> Int -> Int -> SmallArray a -> SmallArray a
+unsafeAdjustWithSize fn index size array =
+  runST $ do
+    m <- thawSmallArray array 0 size
+    element <- readSmallArray m index
+    writeSmallArray m index $! fn element
+    unsafeFreezeSmallArray m
+
 {-# INLINE cons #-}
 cons :: a -> SmallArray a -> SmallArray a
 cons a array =
-  {-# SCC "cons" #-} 
-  let
-    size = sizeofSmallArray array
-    newSize = succ size
-    in runSmallArray $ do
-      newMa <- newSmallArray newSize a
-      copySmallArray newMa 1 array 0 size
-      return newMa
+  {-# SCC "cons" #-}
+  let size = sizeofSmallArray array
+      newSize = succ size
+   in runSmallArray $ do
+        newMa <- newSmallArray newSize a
+        copySmallArray newMa 1 array 0 size
+        return newMa
 
 {-# INLINE orderedPair #-}
 orderedPair :: Int -> e -> Int -> e -> SmallArray e
 orderedPair i1 e1 i2 e2 =
-  {-# SCC "orderedPair" #-} 
-  runSmallArray $ if 
-    | i1 < i2 -> do
-      a <- newSmallArray 2 e1
-      writeSmallArray a 1 e2
-      return a
-    | i1 > i2 -> do
-      a <- newSmallArray 2 e1
-      writeSmallArray a 0 e2
-      return a
-    | otherwise -> do
-      a <- newSmallArray 1 e2
-      return a
+  {-# SCC "orderedPair" #-}
+  runSmallArray
+    $ if
+      | i1 < i2 -> do
+          a <- newSmallArray 2 e1
+          writeSmallArray a 1 e2
+          return a
+      | i1 > i2 -> do
+          a <- newSmallArray 2 e1
+          writeSmallArray a 0 e2
+          return a
+      | otherwise -> do
+          a <- newSmallArray 1 e2
+          return a
 
+{-# INLINE findAndReplace #-}
+findAndReplace :: (a -> Maybe a) -> SmallArray a -> SmallArray a
+findAndReplace f array =
+  let size = sizeofSmallArray array
+      iterate index =
+        if index < size
+          then case f (indexSmallArray array index) of
+            Just newElement -> set index newElement array
+            Nothing -> iterate (succ index)
+          else array
+   in iterate 0
+
+{-# INLINE findAndMap #-}
+findAndMap :: (a -> Maybe b) -> SmallArray a -> Maybe b
+findAndMap f array =
+  let size = sizeofSmallArray array
+      iterate index =
+        if index < size
+          then case f (indexSmallArray array index) of
+            Just b -> Just b
+            Nothing -> iterate (succ index)
+          else Nothing
+   in iterate 0
+
 {-# INLINE find #-}
 find :: (a -> Bool) -> SmallArray a -> Maybe a
 find test array =
-  {-# SCC "find" #-} 
-  let
-    !size = sizeofSmallArray array
-    iterate !index = if index < size
-      then let
-        !element = indexSmallArray array index
-        in if test element
-          then Just element
-          else iterate (succ index)
-      else Nothing
-    in iterate 0
+  {-# SCC "find" #-}
+  let !size = sizeofSmallArray array
+      iterate !index =
+        if index < size
+          then
+            let !element = indexSmallArray array index
+             in if test element
+                  then Just element
+                  else iterate (succ index)
+          else Nothing
+   in iterate 0
 
 {-# INLINE findWithIndex #-}
 findWithIndex :: (a -> Bool) -> SmallArray a -> Maybe (Int, a)
 findWithIndex test array =
-  {-# SCC "findWithIndex" #-} 
-  let
-    !size = sizeofSmallArray array
-    iterate !index = if index < size
-      then let
-        !element = indexSmallArray array index
-        in if test element
-          then Just (index, element)
-          else iterate (succ index)
-      else Nothing
-    in iterate 0
+  {-# SCC "findWithIndex" #-}
+  let !size = sizeofSmallArray array
+      iterate !index =
+        if index < size
+          then
+            let !element = indexSmallArray array index
+             in if test element
+                  then Just (index, element)
+                  else iterate (succ index)
+          else Nothing
+   in iterate 0
 
 {-# INLINE elementsUnfoldlM #-}
-elementsUnfoldlM :: Monad m => SmallArray e -> UnfoldlM m e
-elementsUnfoldlM array = UnfoldlM $ \ step initialState -> let
-  !size = sizeofSmallArray array
-  iterate index !state = if index < size
-    then do
-      element <- indexSmallArrayM array index
-      newState <- step state element
-      iterate (succ index) newState
-    else return state
-  in iterate 0 initialState
+elementsUnfoldlM :: (Monad m) => SmallArray e -> UnfoldlM m e
+elementsUnfoldlM array = UnfoldlM $ \step initialState ->
+  let !size = sizeofSmallArray array
+      iterate index !state =
+        if index < size
+          then do
+            element <- indexSmallArrayM array index
+            newState <- step state element
+            iterate (succ index) newState
+          else return state
+   in iterate 0 initialState
 
 {-# INLINE elementsListT #-}
-elementsListT :: Monad m => SmallArray a -> ListT m a
+elementsListT :: (Monad m) => SmallArray a -> ListT m a
 elementsListT = ListT.fromFoldable
 
 {-# INLINE onFoundElementFocus #-}
-onFoundElementFocus :: Monad m => (a -> Bool) -> (a -> Bool) -> Focus a m b -> Focus (SmallArray a) m b
-onFoundElementFocus testAsKey testWholeEntry (Focus concealA revealA) = Focus concealArray revealArray where
-  concealArray = fmap (fmap arrayChange) concealA where
-    arrayChange = \ case
-      Focus.Set newEntry -> Focus.Set (pure newEntry)
-      _ -> Focus.Leave
-  revealArray array = case findWithIndex testAsKey array of
-    Just (index, entry) -> fmap (fmap arrayChange) (revealA entry) where
-      arrayChange = \ case
-        Focus.Leave -> Focus.Leave
-        Focus.Set newEntry -> if testWholeEntry newEntry
-          then Focus.Leave
-          else Focus.Set (set index newEntry array)
-        Focus.Remove -> if sizeofSmallArray array > 1
-          then Focus.Set (unset index array)
-          else Focus.Remove
-    Nothing -> fmap (fmap arrayChange) concealA where
-      arrayChange = \ case
-        Focus.Set newEntry -> Focus.Set (cons newEntry array)
-        _ -> Focus.Leave
+onFoundElementFocus :: (Monad m) => (a -> Bool) -> (a -> Bool) -> Focus a m b -> Focus (SmallArray a) m b
+onFoundElementFocus testAsKey testWholeEntry (Focus concealA revealA) = Focus concealArray revealArray
+  where
+    concealArray = fmap (fmap arrayChange) concealA
+      where
+        arrayChange = \case
+          Focus.Set newEntry -> Focus.Set (pure newEntry)
+          _ -> Focus.Leave
+    revealArray array = case findWithIndex testAsKey array of
+      Just (index, entry) -> fmap (fmap arrayChange) (revealA entry)
+        where
+          arrayChange = \case
+            Focus.Leave -> Focus.Leave
+            Focus.Set newEntry ->
+              if testWholeEntry newEntry
+                then Focus.Leave
+                else Focus.Set (set index newEntry array)
+            Focus.Remove ->
+              if sizeofSmallArray array > 1
+                then Focus.Set (unset index array)
+                else Focus.Remove
+      Nothing -> fmap (fmap arrayChange) concealA
+        where
+          arrayChange = \case
+            Focus.Set newEntry -> Focus.Set (cons newEntry array)
+            _ -> Focus.Leave
 
 {-# INLINE focusOnFoundElement #-}
-focusOnFoundElement :: Monad m => Focus a m b -> (a -> Bool) -> (a -> Bool) -> SmallArray a -> m (b, SmallArray a)
+focusOnFoundElement :: (Monad m) => Focus a m b -> (a -> Bool) -> (a -> Bool) -> SmallArray a -> m (b, SmallArray a)
 focusOnFoundElement focus testAsKey testWholeEntry = case onFoundElementFocus testAsKey testWholeEntry focus of
-  Focus conceal reveal -> \ sa -> do
+  Focus conceal reveal -> \sa -> do
     (b, change) <- reveal sa
     return $ (b,) $ case change of
       Focus.Leave -> sa
diff --git a/library/PrimitiveExtras/SparseSmallArray.hs b/library/PrimitiveExtras/SparseSmallArray.hs
deleted file mode 100644
--- a/library/PrimitiveExtras/SparseSmallArray.hs
+++ /dev/null
@@ -1,188 +0,0 @@
-module PrimitiveExtras.SparseSmallArray
-(
-  SparseSmallArray,
-  empty,
-  singleton,
-  maybeList,
-  pair,
-  insert,
-  replace,
-  unset,
-  lookup,
-  focusAt,
-  toMaybeList,
-  toIndexedList,
-  elementsUnfoldl,
-  elementsUnfoldlM,
-  elementsListT,
-  onElementAtFocus,
-  null,
-)
-where
-
-import PrimitiveExtras.Prelude hiding (lookup, empty, insert, null)
-import PrimitiveExtras.Types
-import qualified PrimitiveExtras.Prelude as Prelude
-import qualified PrimitiveExtras.Bitmap as Bitmap
-import qualified PrimitiveExtras.SmallArray as SmallArray
-import qualified Focus
-import qualified Control.Foldl as Foldl
-
-
-instance Show a => Show (SparseSmallArray a) where
-  show = show . toMaybeList
-
-deriving instance Eq a => Eq (SparseSmallArray a)
-
-instance Foldable SparseSmallArray where
-  {-# INLINE foldr #-}
-  foldr step state = foldr step state . elementsUnfoldl
-  {-# INLINE foldl' #-}
-  foldl' step state = foldl' step state . elementsUnfoldl
-  {-# INLINE foldMap #-}
-  foldMap monoid = foldMap monoid . elementsUnfoldl
-
-{-# INLINE empty #-}
-empty :: SparseSmallArray e
-empty = SparseSmallArray Bitmap.empty Prelude.empty
-
--- |
--- An array with a single element at the specified index.
-{-# INLINE singleton #-}
-singleton :: Int -> e -> SparseSmallArray e
-singleton i e = 
-  let b = Bitmap.singleton i
-      a = runST $ newSmallArray 1 e >>= unsafeFreezeSmallArray
-      in SparseSmallArray b a
-
-{-# INLINE pair #-}
-pair :: Int -> e -> Int -> e -> SparseSmallArray e
-pair i1 e1 i2 e2 =
-  {-# SCC "pair" #-} 
-  SparseSmallArray bitmap array
-  where 
-    bitmap = Bitmap.pair i1 i2
-    array = SmallArray.orderedPair i1 e1 i2 e2
-
-{-# INLINE maybeList #-}
-maybeList :: [Maybe e] -> SparseSmallArray e
-maybeList list =
-  SparseSmallArray (Bitmap.boolList (map isJust list)) (SmallArray.list (catMaybes list))
-
-{-|
-Insert an element value at the index.
-It's your obligation to ensure that the index is empty before the operation.
--}
-{-# INLINE insert #-}
-insert :: Int -> e -> SparseSmallArray e -> SparseSmallArray e
-insert i e (SparseSmallArray b a) =
-  {-# SCC "insert" #-} 
-  let
-    sparseIndex = Bitmap.populatedIndex i b
-    in SparseSmallArray (Bitmap.insert i b) (SmallArray.insert sparseIndex e a)
-    
-{-# INLINE replace #-}
-replace :: Int -> e -> SparseSmallArray e -> SparseSmallArray e
-replace i e (SparseSmallArray b a) =
-  {-# SCC "replace" #-} 
-  let
-    sparseIndex = Bitmap.populatedIndex i b
-    in SparseSmallArray b (SmallArray.set sparseIndex e a)
-
--- |
--- Remove an element.
-{-# INLINE unset #-}
-unset :: Int -> SparseSmallArray e -> SparseSmallArray e
-unset i (SparseSmallArray b a) =
-  {-# SCC "unset" #-}
-  if Bitmap.isPopulated i b
-    then
-      let
-        sparseIndex = Bitmap.populatedIndex i b
-        b' = Bitmap.invert i b
-        a' = SmallArray.unset sparseIndex a
-        in SparseSmallArray b' a'
-    else SparseSmallArray b a
-
--- |
--- Lookup an item at the index.
-{-# INLINE lookup #-}
-lookup :: Int -> SparseSmallArray e -> Maybe e
-lookup i (SparseSmallArray b a) =
-  {-# SCC "lookup" #-} 
-  if Bitmap.isPopulated i b
-    then Just (indexSmallArray a (Bitmap.populatedIndex i b))
-    else Nothing
-
--- |
--- Convert into a list representation.
-{-# INLINE toMaybeList #-}
-toMaybeList :: SparseSmallArray e -> [Maybe e]
-toMaybeList ssa = do
-  i <- Bitmap.allBitsList
-  return (lookup i ssa)
-
-{-# INLINE toIndexedList #-}
-toIndexedList :: SparseSmallArray e -> [(Int, e)]
-toIndexedList = catMaybes . zipWith (\i -> fmap (i,)) [0..] . toMaybeList
-
-{-# INLINE elementsUnfoldl #-}
-elementsUnfoldl :: SparseSmallArray e -> Unfoldl e
-elementsUnfoldl (SparseSmallArray _ array) = Unfoldl (\ f z -> foldl' f z array)
-
-{-# INLINE elementsUnfoldlM #-}
-elementsUnfoldlM :: Monad m => SparseSmallArray a -> UnfoldlM m a
-elementsUnfoldlM (SparseSmallArray _ array) = SmallArray.elementsUnfoldlM array
-
-{-# INLINE elementsListT #-}
-elementsListT :: SparseSmallArray a -> ListT STM a
-elementsListT (SparseSmallArray _ array) = SmallArray.elementsListT array
-
-{-# INLINE onElementAtFocus #-}
-onElementAtFocus :: Monad m => Int -> Focus a m b -> Focus (SparseSmallArray a) m b
-onElementAtFocus index (Focus concealA revealA) = Focus concealSsa revealSsa where
-  concealSsa = fmap (fmap aChangeToSsaChange) concealA where
-    aChangeToSsaChange = \ case
-      Focus.Leave -> Focus.Leave
-      Focus.Set a -> Focus.Set (SparseSmallArray (Bitmap.singleton index) (pure a))
-      Focus.Remove -> Focus.Leave
-  revealSsa (SparseSmallArray indices array) =
-    fmap (fmap aChangeToSsaChange) $
-    if Bitmap.isPopulated index indices 
-      then do
-        a <- indexSmallArrayM array (Bitmap.populatedIndex index indices)
-        revealA a
-      else concealA
-    where
-      sparseIndex = Bitmap.populatedIndex index indices
-      aChangeToSsaChange = \ case
-        Focus.Leave -> Focus.Leave
-        Focus.Set a -> if Bitmap.isPopulated index indices
-          then let
-            newArray = SmallArray.set sparseIndex a array
-            in Focus.Set (SparseSmallArray indices newArray)
-          else let
-            newIndices = Bitmap.insert index indices
-            newArray = SmallArray.insert sparseIndex a array
-            in Focus.Set (SparseSmallArray newIndices newArray)
-        Focus.Remove -> let
-          newIndices = Bitmap.invert index indices
-          in if Bitmap.null newIndices
-            then Focus.Remove
-            else let
-              newArray = SmallArray.unset sparseIndex array
-              in Focus.Set (SparseSmallArray newIndices newArray)
-
-{-# INLINE focusAt #-}
-focusAt :: Monad m => Focus a m b -> Int -> SparseSmallArray a -> m (b, SparseSmallArray a)
-focusAt aFocus index = case onElementAtFocus index aFocus of
-  Focus conceal reveal -> \ ssa -> do
-    (b, change) <- reveal ssa
-    return $ (b,) $ case change of
-      Focus.Leave -> ssa
-      Focus.Set newSsa -> newSsa
-      Focus.Remove -> empty
-
-{-# INLINE null #-}
-null :: SparseSmallArray a -> Bool
-null (SparseSmallArray bm _) = Bitmap.null bm
diff --git a/library/PrimitiveExtras/TVarArray.hs b/library/PrimitiveExtras/TVarArray.hs
deleted file mode 100644
--- a/library/PrimitiveExtras/TVarArray.hs
+++ /dev/null
@@ -1,33 +0,0 @@
-module PrimitiveExtras.TVarArray
-(
-  TVarArray,
-  new,
-  freezeAsPrimArray,
-  modifyAt,
-)
-where
-
-import PrimitiveExtras.Prelude
-import PrimitiveExtras.Types
-import qualified PrimitiveExtras.UnliftedArray as UnliftedArray
-
-
-new :: a -> Int -> IO (TVarArray a)
-new a size = TVarArray <$> UnliftedArray.replicateIO size (newTVarIO a)
-
-freezeAsPrimArray :: Prim a => TVarArray a -> IO (PrimArray a)
-freezeAsPrimArray (TVarArray varArray) =
-  do
-    let size = sizeofUnliftedArray varArray
-    mpa <- newPrimArray size
-    forMFromZero_ size $ \ index -> do
-      var <- indexUnliftedArrayM varArray index
-      value <- atomically (readTVar var)
-      writePrimArray mpa index value
-    unsafeFreezePrimArray mpa
-
-modifyAt :: TVarArray a -> Int -> (a -> a) -> IO ()
-modifyAt (TVarArray array) index fn =
-  do
-    var <- indexUnliftedArrayM array index
-    atomically $ modifyTVar' var fn
diff --git a/library/PrimitiveExtras/Types.hs b/library/PrimitiveExtras/Types.hs
--- a/library/PrimitiveExtras/Types.hs
+++ b/library/PrimitiveExtras/Types.hs
@@ -1,20 +1,14 @@
-module PrimitiveExtras.Types
-where
+module PrimitiveExtras.Types where
 
 import PrimitiveExtras.Prelude
 
-
 newtype PrimMultiArray a = PrimMultiArray (UnliftedArray (PrimArray a))
 
-newtype TVarArray a = TVarArray (UnliftedArray (TVar a))
-
-{-|
-An immutable space-efficient sparse array, 
-which can only store not more than 32 or 64 elements depending on the system architecure.
--}
-data SparseSmallArray e = SparseSmallArray !Bitmap !(SmallArray e)
+-- |
+-- An immutable space-efficient sparse array,
+-- which can only store not more than 64 elements.
+data By6Bits e = By6Bits {-# UNPACK #-} !Bitmap {-# UNPACK #-} !(SmallArray e)
 
-{-|
-A word-size set of ints.
--}
-newtype Bitmap = Bitmap Int
+-- |
+-- A word-size set of ints.
+newtype Bitmap = Bitmap Int64
diff --git a/library/PrimitiveExtras/UnliftedArray.hs b/library/PrimitiveExtras/UnliftedArray.hs
--- a/library/PrimitiveExtras/UnliftedArray.hs
+++ b/library/PrimitiveExtras/UnliftedArray.hs
@@ -1,54 +1,49 @@
-module PrimitiveExtras.UnliftedArray
-where
+module PrimitiveExtras.UnliftedArray where
 
 import PrimitiveExtras.Prelude
 
-
 {-# INLINE at #-}
-at :: PrimUnlifted element => UnliftedArray element -> Int -> forall result. result -> (element -> result) -> result
+at :: (PrimUnlifted element) => UnliftedArray element -> Int -> forall result. result -> (element -> result) -> result
 at ua index none some =
   if sizeofUnliftedArray ua <= index
     then none
     else some (indexUnliftedArray ua index)
 
-{-# INLINABLE replicateIO #-}
-replicateIO :: PrimUnlifted a => Int -> IO a -> IO (UnliftedArray a)
+{-# INLINEABLE replicateIO #-}
+replicateIO :: (PrimUnlifted a) => Int -> IO a -> IO (UnliftedArray a)
 replicateIO size elementIO =
   do
     array <- unsafeNewUnliftedArray size
-    let
-      loop index =
-        if index < size
-          then do
-            element <- elementIO
-            writeUnliftedArray array index element
-            loop (succ index)
-          else unsafeFreezeUnliftedArray array
-      in loop 0
+    let loop index =
+          if index < size
+            then do
+              element <- elementIO
+              writeUnliftedArray array index element
+              loop (succ index)
+            else unsafeFreezeUnliftedArray array
+     in loop 0
 
-{-# INLINABLE generate #-}
-generate :: PrimUnlifted a => Int -> (Int -> IO a) -> IO (UnliftedArray a)
+{-# INLINEABLE generate #-}
+generate :: (PrimUnlifted a) => Int -> (Int -> IO a) -> IO (UnliftedArray a)
 generate size elementIO =
   do
     array <- unsafeNewUnliftedArray size
-    let
-      loop index =
-        if index < size
-          then do
-            element <- elementIO index
-            writeUnliftedArray array index element
-            loop (succ index)
-          else unsafeFreezeUnliftedArray array
-      in loop 0
+    let loop index =
+          if index < size
+            then do
+              element <- elementIO index
+              writeUnliftedArray array index element
+              loop (succ index)
+            else unsafeFreezeUnliftedArray array
+     in loop 0
 
 traverse_ :: (Monad m, PrimUnlifted a) => (a -> m ()) -> UnliftedArray a -> m ()
 traverse_ action array =
-  let
-    size = sizeofUnliftedArray array
-    iterate index = if index < size
-      then do
-        element <- indexUnliftedArrayM array index
-        action element
-        iterate (succ index)
-      else return ()
-    in iterate 0
+  let size = sizeofUnliftedArray array
+      iterate index =
+        if index < size
+          then do
+            action (indexUnliftedArray array index)
+            iterate (succ index)
+          else return ()
+   in iterate 0
diff --git a/primitive-extras.cabal b/primitive-extras.cabal
--- a/primitive-extras.cabal
+++ b/primitive-extras.cabal
@@ -1,68 +1,146 @@
+cabal-version: 3.0
 name: primitive-extras
-version: 0.7.1.1
-category: Primitive
 synopsis: Extras for the "primitive" library
-homepage: https://github.com/metrix-ai/primitive-extras
-bug-reports: https://github.com/metrix-ai/primitive-extras/issues
+description:
+  Raw collection of extra utiltilies for the "primitive" library.
+
+version: 0.10.2.2
+category: Primitive
+homepage: https://github.com/nikita-volkov/primitive-extras
+bug-reports: https://github.com/nikita-volkov/primitive-extras/issues
 author: Nikita Volkov <nikita.y.volkov@mail.ru>
-maintainer: Metrix.AI Tech Team <tech@metrix.ai>
+maintainer: Nikita Volkov <nikita.y.volkov@mail.ru>
 copyright: (c) 2018, Metrix.AI
 license: MIT
 license-file: LICENSE
-build-type: Simple
-cabal-version: >=1.10
 
 source-repository head
   type: git
-  location: git://github.com/metrix-ai/primitive-extras.git
+  location: git://github.com/nikita-volkov/primitive-extras.git
 
 library
   hs-source-dirs: library
-  default-extensions: Arrows, BangPatterns, ConstraintKinds, DataKinds, DefaultSignatures, DeriveDataTypeable, DeriveFoldable, DeriveFunctor, DeriveGeneric, DeriveTraversable, EmptyDataDecls, FlexibleContexts, FlexibleInstances, FunctionalDependencies, GADTs, GeneralizedNewtypeDeriving, LambdaCase, LiberalTypeSynonyms, MagicHash, MultiParamTypeClasses, MultiWayIf, NoImplicitPrelude, NoMonomorphismRestriction, OverloadedStrings, PatternGuards, ParallelListComp, QuasiQuotes, RankNTypes, RecordWildCards, ScopedTypeVariables, StandaloneDeriving, TemplateHaskell, TupleSections, TypeFamilies, TypeOperators, UnboxedTuples
+  default-extensions:
+    Arrows
+    BangPatterns
+    ConstraintKinds
+    DataKinds
+    DefaultSignatures
+    DeriveDataTypeable
+    DeriveFoldable
+    DeriveFunctor
+    DeriveGeneric
+    DeriveTraversable
+    EmptyDataDecls
+    FlexibleContexts
+    FlexibleInstances
+    FunctionalDependencies
+    GADTs
+    GeneralizedNewtypeDeriving
+    LambdaCase
+    LiberalTypeSynonyms
+    MagicHash
+    MultiParamTypeClasses
+    MultiWayIf
+    NoImplicitPrelude
+    NoMonomorphismRestriction
+    OverloadedStrings
+    ParallelListComp
+    PatternGuards
+    QuasiQuotes
+    RankNTypes
+    RecordWildCards
+    ScopedTypeVariables
+    StandaloneDeriving
+    TemplateHaskell
+    TupleSections
+    TypeFamilies
+    TypeOperators
+    UnboxedTuples
+
   default-language: Haskell2010
   exposed-modules:
     PrimitiveExtras.Bitmap
-    PrimitiveExtras.SmallArray
-    PrimitiveExtras.SparseSmallArray
-    PrimitiveExtras.TVarArray
+    PrimitiveExtras.By6Bits
     PrimitiveExtras.PrimArray
-    PrimitiveExtras.UnliftedArray
     PrimitiveExtras.PrimMultiArray
+    PrimitiveExtras.SmallArray
+    PrimitiveExtras.UnliftedArray
+
   other-modules:
+    PrimitiveExtras.FoldMs
+    PrimitiveExtras.Folds
     PrimitiveExtras.Prelude
     PrimitiveExtras.Types
-    PrimitiveExtras.Folds
-    PrimitiveExtras.FoldMs
+
   build-depends:
     base >=4.7 && <5,
-    bytestring >=0.10 && <0.11,
+    bytestring >=0.10 && <0.13,
     cereal >=0.5.5 && <0.6,
     deferred-folds >=0.9 && <0.10,
     focus >=1 && <1.1,
     foldl >=1 && <2,
     list-t >=1.0.1 && <1.1,
-    primitive >=0.6.4 && <0.8,
+    primitive >=0.7 && <0.10,
+    primitive-unlifted >=0.1.3.1 && <0.2 || >=2.1 && <2.3,
     profunctors >=5 && <6,
-    vector >=0.12 && <0.13
+    vector >=0.12 && <0.14,
 
 test-suite test
   type: exitcode-stdio-1.0
   hs-source-dirs: test
   main-is: Main.hs
-  default-extensions: Arrows, BangPatterns, ConstraintKinds, DataKinds, DefaultSignatures, DeriveDataTypeable, DeriveFoldable, DeriveFunctor, DeriveGeneric, DeriveTraversable, EmptyDataDecls, FlexibleContexts, FlexibleInstances, FunctionalDependencies, GADTs, GeneralizedNewtypeDeriving, LambdaCase, LiberalTypeSynonyms, MagicHash, MultiParamTypeClasses, MultiWayIf, NoImplicitPrelude, NoMonomorphismRestriction, OverloadedStrings, PatternGuards, ParallelListComp, QuasiQuotes, RankNTypes, RecordWildCards, ScopedTypeVariables, StandaloneDeriving, TemplateHaskell, TupleSections, TypeFamilies, TypeOperators, UnboxedTuples
+  default-extensions:
+    Arrows
+    BangPatterns
+    ConstraintKinds
+    DataKinds
+    DefaultSignatures
+    DeriveDataTypeable
+    DeriveFoldable
+    DeriveFunctor
+    DeriveGeneric
+    DeriveTraversable
+    EmptyDataDecls
+    FlexibleContexts
+    FlexibleInstances
+    FunctionalDependencies
+    GADTs
+    GeneralizedNewtypeDeriving
+    LambdaCase
+    LiberalTypeSynonyms
+    MagicHash
+    MultiParamTypeClasses
+    MultiWayIf
+    NoImplicitPrelude
+    NoMonomorphismRestriction
+    OverloadedStrings
+    ParallelListComp
+    PatternGuards
+    QuasiQuotes
+    RankNTypes
+    RecordWildCards
+    ScopedTypeVariables
+    StandaloneDeriving
+    TemplateHaskell
+    TupleSections
+    TypeFamilies
+    TypeOperators
+    UnboxedTuples
+
   default-language: Haskell2010
   other-modules:
     Main.Gens
     Main.Transaction
+
   build-depends:
+    QuickCheck >=2.13.1 && <3,
     cereal,
     deferred-folds,
     focus,
     primitive,
     primitive-extras,
-    QuickCheck >=2.8.1 && <3,
-    quickcheck-instances >=0.3.11 && <0.4,
     rerebase <2,
-    tasty >=0.12 && <2,
-    tasty-hunit >=0.9 && <0.11,
-    tasty-quickcheck >=0.9 && <0.11
+    tasty >=1.2.2 && <2,
+    tasty-hunit >=0.10.0.2 && <0.11,
+    tasty-quickcheck >=0.10.1 && <0.12,
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -1,131 +1,118 @@
 module Main where
 
-import Prelude hiding (choose)
 import Data.Primitive
-import Test.QuickCheck.Instances
-import Test.Tasty
-import Test.Tasty.Runners
-import Test.Tasty.HUnit
-import Test.Tasty.QuickCheck
-import PrimitiveExtras.SparseSmallArray (SparseSmallArray)
+import qualified Data.Serialize as Serialize
+import qualified Data.Vector.Primitive as PrimitiveVector
 import qualified Focus
-import qualified Test.QuickCheck as QuickCheck
-import qualified Test.QuickCheck.Property as QuickCheck
-import qualified Main.Transaction as Transaction
 import qualified Main.Gens as Gen
-import qualified PrimitiveExtras.SparseSmallArray as SparseSmallArray
-import qualified PrimitiveExtras.SmallArray as SmallArray
+import qualified Main.Transaction as Transaction
+import PrimitiveExtras.By6Bits (By6Bits)
+import qualified PrimitiveExtras.By6Bits as By6Bits
 import qualified PrimitiveExtras.PrimArray as PrimArray
-import qualified Data.Serialize as Serialize
-import qualified Data.Vector.Primitive as PrimitiveVector
-
+import qualified PrimitiveExtras.SmallArray as SmallArray
+import qualified Test.QuickCheck as QuickCheck
+import Test.Tasty
+import Test.Tasty.HUnit
+import Test.Tasty.QuickCheck
+import Prelude hiding (choose)
 
+main :: IO ()
 main =
-  defaultMain $
-  testGroup "All" $
-  [
-    testGroup "SmallArray" $
-    [
-      testCase "set" $ let
-        array = SmallArray.list [1, 2, 3]
-        in assertEqual ""
-          [1, 4, 3]
-          (SmallArray.toList (SmallArray.set 1 4 array))
-      ,
-      testCase "insert" $ let
-        array = SmallArray.list [1, 2, 3]
-        in assertEqual ""
-          [1, 4, 2, 3]
-          (SmallArray.toList (SmallArray.insert 1 4 array))
-      ,
-      testCase "unset" $ let
-        array = SmallArray.list [1, 2, 3]
-        in assertEqual ""
-          [1, 3]
-          (SmallArray.toList (SmallArray.unset 1 array))
-      ,
-      testCase "focus insert, when exists" $ let
-        array = SmallArray.list [1, 2, 3]
-        in assertEqual ""
-          [1, 4, 3]
-          (SmallArray.toList (snd (runIdentity (SmallArray.focusOnFoundElement (Focus.insert 4) (== 2) (const False) array))))
-      ,
-      testCase "focus insert, when doesn't exist" $ let
-        array = SmallArray.list [1, 2, 3]
-        in assertEqual ""
-          [4, 1, 2, 3]
-          (SmallArray.toList (snd (runIdentity (SmallArray.focusOnFoundElement (Focus.insert 4) (== 4) (const False) array))))
-      ,
-      testCase "focus delete" $ let
-        array = SmallArray.list [1, 2, 3]
-        in assertEqual ""
-          [1, 3]
-          (SmallArray.toList (snd (runIdentity (SmallArray.focusOnFoundElement Focus.delete (== 2) (const False) array))))
-    ]
-    ,
-    testGroup "SparseSmallArray" $
-    [
-      testCase "empty" $ do
-        assertEqual ""
-          (replicate (finiteBitSize (undefined :: Int)) Nothing)
-          (SparseSmallArray.toMaybeList (SparseSmallArray.empty :: SparseSmallArray Int32))
-      ,
-      testProperty "toMaybeList, maybeList" $ forAll Gen.maybeList $ \ maybeList ->
-      maybeList === SparseSmallArray.toMaybeList (SparseSmallArray.maybeList maybeList)
-      ,
-      testCase "unset" $ assertEqual ""
-        ([Just 1, Nothing, Nothing, Just 3] <> replicate (finiteBitSize (undefined :: Int) - 4) Nothing)
-        (SparseSmallArray.toMaybeList (SparseSmallArray.unset 1 (SparseSmallArray.maybeList [Just 1, Just 2, Nothing, Just 3])))
-      ,
-      testTransactionProperty "set" Gen.setTransaction
-      ,
-      testTransactionProperty "unset" Gen.unsetTransaction
-      ,
-      testTransactionProperty "focusInsert" Gen.focusInsertTransaction
-      ,
-      testTransactionProperty "focusDelete" Gen.focusDeleteTransaction
-      ,
-      testTransactionProperty "unfoldl" Gen.unfoldlTransaction
-      ,
-      testTransactionProperty "lookup" Gen.lookupTransaction
-      ,
-      testTransactionProperty "composite" Gen.transaction
-    ]
-    ,
-    testGroup "PrimArray" $
-    [
-      testProperty "Construction from primitive vector" $ let
-        gen = do
-          offset <- choose (0, 2)
-          length <- choose (0, 100)
-          listSize <- let
-            minSize = offset + length
-            in choose (minSize, minSize + 100)
-          list :: [Int32] <- replicateM listSize arbitrary
-          return (list, offset, length)
-        in forAll gen $ \ (inputList, offset, length) -> let
-          !inputVec = PrimitiveVector.fromList inputList
-          !sliceVec = PrimitiveVector.slice offset length inputVec
-          !sliceList = PrimitiveVector.toList sliceVec
-          in sliceList === primArrayToList (PrimArray.primitiveVector sliceVec)
-      ,
-      testProperty "Serializes well with as in memory" $ forAll (Gen.primArray Gen.element) $ \ primArray ->
-      Right primArray ===
-      Serialize.runGet (PrimArray.cerealGetAsInMemory Serialize.get)
-          (Serialize.runPut ((PrimArray.cerealPutAsInMemory Serialize.put) primArray))
-    ]
-  ]
+  defaultMain
+    $ testGroup "All"
+    $ [ testGroup "SmallArray"
+          $ [ testCase "set"
+                $ let array = SmallArray.list [1, 2, 3]
+                   in assertEqual
+                        ""
+                        [1, 4, 3]
+                        (SmallArray.toList (SmallArray.set 1 4 array)),
+              testCase "insert"
+                $ let array = SmallArray.list [1, 2, 3]
+                   in assertEqual
+                        ""
+                        [1, 4, 2, 3]
+                        (SmallArray.toList (SmallArray.insert 1 4 array)),
+              testCase "unset"
+                $ let array = SmallArray.list [1, 2, 3]
+                   in assertEqual
+                        ""
+                        [1, 3]
+                        (SmallArray.toList (SmallArray.unset 1 array)),
+              testCase "focus insert, when exists"
+                $ let array = SmallArray.list [1, 2, 3]
+                   in assertEqual
+                        ""
+                        [1, 4, 3]
+                        (SmallArray.toList (snd (runIdentity (SmallArray.focusOnFoundElement (Focus.insert 4) (== 2) (const False) array)))),
+              testCase "focus insert, when doesn't exist"
+                $ let array = SmallArray.list [1, 2, 3]
+                   in assertEqual
+                        ""
+                        [4, 1, 2, 3]
+                        (SmallArray.toList (snd (runIdentity (SmallArray.focusOnFoundElement (Focus.insert 4) (== 4) (const False) array)))),
+              testCase "focus delete"
+                $ let array = SmallArray.list [1, 2, 3]
+                   in assertEqual
+                        ""
+                        [1, 3]
+                        (SmallArray.toList (snd (runIdentity (SmallArray.focusOnFoundElement Focus.delete (== 2) (const False) array))))
+            ],
+        testGroup "By6Bits"
+          $ [ testCase "empty" $ do
+                assertEqual
+                  ""
+                  (replicate (finiteBitSize (undefined :: Int)) Nothing)
+                  (By6Bits.toMaybeList (By6Bits.empty :: By6Bits Int32)),
+              testProperty "toMaybeList, maybeList" $ forAll Gen.maybeList $ \maybeList ->
+                maybeList === By6Bits.toMaybeList (By6Bits.maybeList maybeList),
+              testCase "unset"
+                $ assertEqual
+                  ""
+                  ([Just 1, Nothing, Nothing, Just 3] <> replicate (finiteBitSize (undefined :: Int) - 4) Nothing)
+                  (By6Bits.toMaybeList (By6Bits.unset 1 (By6Bits.maybeList [Just 1, Just 2, Nothing, Just 3]))),
+              testTransactionProperty "set" Gen.setTransaction,
+              testTransactionProperty "unset" Gen.unsetTransaction,
+              testTransactionProperty "focusInsert" Gen.focusInsertTransaction,
+              testTransactionProperty "focusDelete" Gen.focusDeleteTransaction,
+              testTransactionProperty "unfoldl" Gen.unfoldlTransaction,
+              testTransactionProperty "lookup" Gen.lookupTransaction,
+              testTransactionProperty "composite" Gen.transaction
+            ],
+        testGroup "PrimArray"
+          $ [ testProperty "Construction from primitive vector"
+                $ let gen = do
+                        offset <- choose (0, 2)
+                        length <- choose (0, 100)
+                        listSize <-
+                          let minSize = offset + length
+                           in choose (minSize, minSize + 100)
+                        list :: [Int32] <- replicateM listSize arbitrary
+                        return (list, offset, length)
+                   in forAll gen $ \(inputList, offset, length) ->
+                        let !inputVec = PrimitiveVector.fromList inputList
+                            !sliceVec = PrimitiveVector.slice offset length inputVec
+                            !sliceList = PrimitiveVector.toList sliceVec
+                         in sliceList === primArrayToList (PrimArray.primitiveVector sliceVec),
+              testProperty "Serializes well with as in memory" $ forAll (Gen.primArray Gen.element) $ \primArray ->
+                Right primArray
+                  === Serialize.runGet
+                    (PrimArray.cerealGetAsInMemory Serialize.get)
+                    (Serialize.runPut ((PrimArray.cerealPutAsInMemory Serialize.put) primArray))
+            ]
+      ]
 
+testTransactionProperty :: String -> Gen (Transaction.Transaction Int) -> TestTree
 testTransactionProperty name transactionGen =
-  testProperty (showString "Transaction: " name) $
-  forAll ((,) <$> Gen.maybeList <*> transactionGen) $ \ (maybeList, transaction) ->
-  case transaction of
-    Transaction.Transaction name applyToMaybeList applyToSparseSmallArray -> let
-      ssa = SparseSmallArray.maybeList maybeList
-      (result1, newMaybeList) = runState applyToMaybeList maybeList
-      (result2, newSsa) = runState applyToSparseSmallArray ssa
-      newSsaMaybeList = SparseSmallArray.toMaybeList newSsa
-      in
-        QuickCheck.counterexample
-          ("transaction: " <> show name <> "\nnewMaybeList1: " <> show newMaybeList <> "\nnewMaybeList2: " <> show newSsaMaybeList <> "\nresult1: " <> show result1 <> "\nresult2: " <> show result2)
-          (newMaybeList == SparseSmallArray.toMaybeList newSsa && result1 == result2)
+  testProperty (showString "Transaction: " name)
+    $ forAll ((,) <$> Gen.maybeList <*> transactionGen)
+    $ \(maybeList, transaction) ->
+      case transaction of
+        Transaction.Transaction name applyToMaybeList applyToBy6Bits ->
+          let ssa = By6Bits.maybeList maybeList
+              (result1, newMaybeList) = runState applyToMaybeList maybeList
+              (result2, newSsa) = runState applyToBy6Bits ssa
+              newSsaMaybeList = By6Bits.toMaybeList newSsa
+           in QuickCheck.counterexample
+                ("transaction: " <> show name <> "\nnewMaybeList1: " <> show newMaybeList <> "\nnewMaybeList2: " <> show newSsaMaybeList <> "\nresult1: " <> show result1 <> "\nresult2: " <> show result2)
+                (newMaybeList == By6Bits.toMaybeList newSsa && result1 == result2)
diff --git a/test/Main/Gens.hs b/test/Main/Gens.hs
--- a/test/Main/Gens.hs
+++ b/test/Main/Gens.hs
@@ -1,13 +1,11 @@
 module Main.Gens where
 
-import Prelude hiding (choose, index)
-import Test.QuickCheck.Gen
-import Focus (Focus(..))
-import Main.Transaction (Transaction)
 import Data.Primitive
+import Main.Transaction (Transaction)
 import qualified Main.Transaction as Transaction
-import qualified PrimitiveExtras.SparseSmallArray as SparseSmallArray
-
+import qualified PrimitiveExtras.By6Bits as By6Bits
+import Test.QuickCheck.Gen
+import Prelude hiding (choose, index)
 
 element :: Gen Int
 element = choose (0, 999)
@@ -36,8 +34,7 @@
 transaction :: Gen (Transaction Int)
 transaction =
   frequency
-    [
-      (9, lookupTransaction),
+    [ (9, lookupTransaction),
       (9, setTransaction),
       (9, unsetTransaction),
       (9, focusInsertTransaction),
@@ -46,17 +43,17 @@
 
 maybeList :: Gen [Maybe Int]
 maybeList =
-  replicateM (finiteBitSize (undefined :: Int)) $ frequency $
-  [
-    (4, fmap Just element),
-    (1, pure Nothing)
-  ]
+  replicateM (finiteBitSize (undefined :: Int))
+    $ frequency
+    $ [ (4, fmap Just element),
+        (1, pure Nothing)
+      ]
 
-sparseSmallArray :: Gen (SparseSmallArray.SparseSmallArray Int)
+sparseSmallArray :: Gen (By6Bits.By6Bits Int)
 sparseSmallArray =
-  SparseSmallArray.maybeList <$> maybeList
+  By6Bits.maybeList <$> maybeList
 
-primArray :: Prim a => Gen a -> Gen (PrimArray a)
+primArray :: (Prim a) => Gen a -> Gen (PrimArray a)
 primArray aGen = do
   list <- listOf aGen
   return (primArrayFromList list)
diff --git a/test/Main/Transaction.hs b/test/Main/Transaction.hs
--- a/test/Main/Transaction.hs
+++ b/test/Main/Transaction.hs
@@ -1,113 +1,109 @@
+{-# OPTIONS_GHC -Wno-redundant-constraints #-}
+
 module Main.Transaction where
 
-import Prelude
-import Focus (Focus(..))
-import qualified Focus
-import qualified PrimitiveExtras.SparseSmallArray as SparseSmallArray
 import qualified Data.Text as Text
 import qualified DeferredFolds.Unfoldl as Unfoldl
-
+import Focus (Focus (..))
+import qualified Focus
+import qualified PrimitiveExtras.By6Bits as By6Bits
+import Prelude
 
-data Transaction element = forall result. (Show result, Eq result) => Transaction {
-  name :: Text,
-  applyToMaybeList :: State [Maybe element] result,
-  applyToSparseSmallArray :: State (SparseSmallArray.SparseSmallArray element) result
-}
+data Transaction element
+  = forall result.
+  (Show result, Eq result) =>
+  Transaction
+  { name :: Text,
+    applyToMaybeList :: State [Maybe element] result,
+    applyToBy6Bits :: State (By6Bits.By6Bits element) result
+  }
 
 instance Show (Transaction element) where
   show = Text.unpack . name
 
-singleton :: Show element => Int -> element -> Transaction element
+singleton :: (Show element) => Int -> element -> Transaction element
 singleton index element =
-  Transaction {
-    name = "singleton " <> (fromString . show) index <> " " <> fromString (show element)
-    ,
-    applyToMaybeList =
-      put $ map (\i' -> if index == i' then Just element else Nothing) [0 .. pred (finiteBitSize (undefined :: Int))]
-    ,
-    applyToSparseSmallArray =
-      put $ SparseSmallArray.singleton index element
-  }
+  Transaction
+    { name = "singleton " <> (fromString . show) index <> " " <> fromString (show element),
+      applyToMaybeList =
+        put $ map (\i' -> if index == i' then Just element else Nothing) [0 .. pred (finiteBitSize (undefined :: Int))],
+      applyToBy6Bits =
+        put $ By6Bits.singleton index element
+    }
 
-set :: Show element => Int -> element -> Transaction element
+set :: (Show element) => Int -> element -> Transaction element
 set index element =
-  Transaction {
-    name = "set " <> (fromString . show) index <> " " <> (fromString . show) element
-    ,
-    applyToMaybeList = do
-      l <- get
-      put $ do
-        (i', e') <- zip [0..] l
-        return $ if index == i' then Just element else e'
-    ,
-    applyToSparseSmallArray = do
-      ssa <- get
-      case SparseSmallArray.lookup index ssa of
-        Just _ -> put (SparseSmallArray.replace index element ssa)
-        Nothing -> put (SparseSmallArray.insert index element ssa)
-  }
+  Transaction
+    { name = "set " <> (fromString . show) index <> " " <> (fromString . show) element,
+      applyToMaybeList = do
+        l <- get
+        put $ do
+          (i', e') <- zip [0 ..] l
+          return $ if index == i' then Just element else e',
+      applyToBy6Bits = do
+        ssa <- get
+        case By6Bits.lookup index ssa of
+          Just _ -> put (By6Bits.replace index element ssa)
+          Nothing -> put (By6Bits.insert index element ssa)
+    }
 
 unset :: Int -> Transaction element
 unset index =
-  Transaction {
-    name = "unset " <> fromString (show index)
-    ,
-    applyToMaybeList = do
-      l <- get
-      put $ do
-        (i', e') <- zip [0..] l
-        return $ if index == i' then Nothing else e'
-    ,
-    applyToSparseSmallArray =
-      get >>= put . (SparseSmallArray.unset index)
-  }
+  Transaction
+    { name = "unset " <> fromString (show index),
+      applyToMaybeList = do
+        l <- get
+        put $ do
+          (i', e') <- zip [0 ..] l
+          return $ if index == i' then Nothing else e',
+      applyToBy6Bits =
+        get >>= put . (By6Bits.unset index)
+    }
 
 lookup :: (Show element, Eq element) => Int -> Transaction element
 lookup index =
-  Transaction {
-    name = "lookup " <> fromString (show index),
-    applyToMaybeList = fmap (join . fmap fst . uncons . drop index) get,
-    applyToSparseSmallArray = fmap (SparseSmallArray.lookup index) get
-  }
+  Transaction
+    { name = "lookup " <> fromString (show index),
+      applyToMaybeList = fmap (join . fmap fst . uncons . drop index) get,
+      applyToBy6Bits = fmap (By6Bits.lookup index) get
+    }
 
 elementsUnfoldl :: (Show element, Eq element) => Transaction element
 elementsUnfoldl =
-  Transaction {
-    name = "elementsUnfoldl",
-    applyToMaybeList = do
-      list <- get
-      return $ do
-        maybeElement <- Unfoldl.foldable list
-        element <- Unfoldl.foldable maybeElement
-        return element,
-    applyToSparseSmallArray = fmap SparseSmallArray.elementsUnfoldl get
-  }
+  Transaction
+    { name = "elementsUnfoldl",
+      applyToMaybeList = do
+        list <- get
+        return $ do
+          maybeElement <- Unfoldl.foldable list
+          element <- Unfoldl.foldable maybeElement
+          return element,
+      applyToBy6Bits = fmap By6Bits.elementsUnfoldl get
+    }
 
 focusAt :: (Show element, Eq result, Show result) => Text -> Focus element Identity result -> Int -> Transaction element
 focusAt focusName focus index =
-  Transaction {
-    name = "focusAt (" <> (fromString . show) index <> " " <> focusName <> ")"
-    ,
-    applyToMaybeList = do
-      list <- get
-      case focus of
-        Focus conceal reveal -> case splitAt index list of
-          (precedingList, elementMaybe : trailingList) -> do
-            (result, change) <- lift (maybe conceal reveal elementMaybe)
-            case change of
-              Focus.Leave -> return ()
-              Focus.Set newElement -> put (precedingList <> [Just newElement] <> trailingList)
-              Focus.Remove -> put (precedingList <> [Nothing] <> trailingList)
-            return result
-          _ -> error "Index out of bounds"
-    ,
-    applyToSparseSmallArray = StateT (SparseSmallArray.focusAt focus index)
-  }
+  Transaction
+    { name = "focusAt (" <> (fromString . show) index <> " " <> focusName <> ")",
+      applyToMaybeList = do
+        list <- get
+        case focus of
+          Focus conceal reveal -> case splitAt index list of
+            (precedingList, elementMaybe : trailingList) -> do
+              (result, change) <- lift (maybe conceal reveal elementMaybe)
+              case change of
+                Focus.Leave -> return ()
+                Focus.Set newElement -> put (precedingList <> [Just newElement] <> trailingList)
+                Focus.Remove -> put (precedingList <> [Nothing] <> trailingList)
+              return result
+            _ -> error "Index out of bounds",
+      applyToBy6Bits = StateT (By6Bits.focusAt focus index)
+    }
 
-focusInsert :: Show element => Int -> element -> Transaction element
+focusInsert :: (Show element) => Int -> element -> Transaction element
 focusInsert index element =
   focusAt ("Insert (" <> (fromString . show) element <> ")") (Focus.insert element) index
 
-focusDelete :: Show element => Int -> Transaction element
+focusDelete :: (Show element) => Int -> Transaction element
 focusDelete index =
   focusAt ("Delete") Focus.delete index
