diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,137 @@
+# Revision history for contiguous
+
+## 0.6.4.1 -- 2024-02-05
+
+* Update package metadata.
+
+## 0.6.4.0 -- 2023-06-28
+
+* Make it work with primitive-unlifted-2.1, which drops
+  support for older primitive-unlifted.
+* Add `quintupleton` and `sextupleton`.
+* Add `construct(1|2|3|4|5|6)` aliases for constructing arrays with
+  a small known number of elements.
+
+## 0.6.3.0 -- 2022-12-07
+
+* Add strict `foldrM`
+
+## 0.6.2.0 -- 2022-04-13
+
+* Make benchmarks build
+* Add strict `ifoldlZipWith` and `foldlZipWith`
+
+## 0.6.1.1 -- 2022-02-16
+
+* Allow building with GHC 9.2.1.
+* Drop support for GHC 8.8 and earlier.
+
+## 0.6.1.0 -- 2021-09-01
+
+* Add `itraverseP`
+* Add `deleteAt` and `ifoldr`
+
+## 0.6.0 -- 2021-08-28
+
+* Add `Slice`, `MutableSlice`.
+* Split `Contiguous` into `ContiguousSlice` and `Contiguous`.
+* Add `shrink` and `unsafeShrinkAndFreeze`
+
+## 0.5.2 -- 2021-08-11
+
+* Add `ifoldlM'`.
+* Add `foldrZipWith` and `ifoldrZipWith`.
+* Add `foldlZipWithM'` and `ifoldlZipWithM'`.
+* Add `all` and `any`.
+* Add `run`. Use it internally to accerelate prevent GHC from
+  boxing results in `runST`.
+* Add `quadrupleton`.
+
+## 0.5.1 -- 2020-06-30
+
+* Add `izipWith`.
+* Compatibility with `primitive-0.7.1.0`.
+
+## 0.5 -- 2019-07-23
+
+* Add `generateM`, `reverseSlice`, `swap`, `catMaybes`,
+  `zipWith`, `zip`, `lefts`, `rights`, `partitionEithers`, `elem`,
+  `find`, `maximum`/`minimum`, `maximumBy`/`minimumBy`, `asum`,
+  `mapM(_)`, `forM(_)`, `for(_)`, `sequence(_)`, `(<$)`, `ap`, `scanl`,
+  `scanl'`, `iscanl`, `iscanl'`, `prescanl`, `prescanl'`, `iprescanl`,
+  `iprescanl'`
+* Re-export Array types from the `primitive` package
+* Expand unit test suite to include all added functions
+* Expand laws test suite to test Foldable/IsList/Traversable laws
+  in addition to Functor/Applicative
+* Add benchmark suite that measures allocations
+* Fix performance issue with fold functions that caused huge increase
+  in allocations when partially-applied. Partially-applied folds now
+  perform as well as fully-applied.
+* Make sure all functions are marked INLINE. Last function not marked
+  as inline was `imap'`.
+
+## 0.4.0.1 -- 2019-05-17
+
+* Allow building with `primitive-0.7`. This required depending on the
+  `primitive-unlifted` package to provide the removed `UnliftedArray`
+  api.
+
+## 0.4 -- 2019-05-16
+
+* Add `convert`, `filter`, `ifilter`, `itraverse(_)` (#6), `imap'`,
+  `unsafeFromListN`, `unsafeFromListReverseMutableN`, `ifoldr'`,
+  `foldl`, `mapMutable`, `imapMutable`, `reverse`, `reverseMutable`,
+  `replicateMutableM`, `create`, `createT`, `unsafeFromListReverseN`,
+  `generate`, `generateMutable`, `iterate`, `iterateMutableN`,
+  `iterateMutableNM`, `unfoldr`, `unfoldrMutable`, `toList`,
+  `toListMutable`, `fromListMutableN`, `fromListMutable`, `fromListN`,
+  `fromList`, `modify`, `modify'`, `enumFromN`, `enumFromMutableN`
+* Refactor `replicate` functions to make more sense (#19)
+* Add `Contiguous` instance for `SmallArray`
+* Attempt to mark everything as inline (#18)
+* Achieve 100% doc coverage, organise exports a lot more
+  (mimicking vector). Various haddock fixes
+* Make `toListMutable` strict in the accumulator
+* Change all instances of `return` to `pure`
+* Add initial test suite (some unit tests that check implementations
+  against base/vector versions of the same functions)
+* Export `unsafeFreeze`, `copy`, `write`,
+* Rename `sameMutable` to `equalsMutable`
+
+## 0.3.3.0 -- 2019-03-24
+
+* Add `freeze` as a method to `Contiguous`
+* Add more folds
+* Mark more functions as INLINEABLE
+
+## 0.3.2.0 -- 2019-01-02
+
+* Add `thaw` as a method to `Contiguous`
+
+## 0.3.1.0 -- 2018-10-19
+
+* Add `singleton`,`doubleton`,`tripleton` as methods to `Contiguous`
+* Add `map'`, `imap`, `mapMutable'`, `imapMutable'`
+
+## 0.3.0.0 -- 2018-09-06
+
+* Document the need for `Always`
+* Generalise API: from `ST s` to `PrimMonad m`
+* Add NFData `rnf` function for deeply evaluating
+  `Contiguous` arrays.
+* Add function `equals`, for detecting if two arrays in memory
+  are the same.
+* Add hashing function.
+* Make `map` able to produce a new array type.
+* Add `replicate`, `null` as methods to `Contiguous`.
+* Add `traverse`, `itraverse`, `traverseP`, `foldMap`
+
+## 0.2.0.0 -- 2018-06-07
+
+* Add cabal metadata: category, proper synopsis/description
+* Use primitive-0.6.4.0
+
+## 0.1.0.0 -- 2018-05-31
+
+* Initial version.
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/bench/Main.hs b/bench/Main.hs
--- a/bench/Main.hs
+++ b/bench/Main.hs
@@ -1,20 +1,21 @@
-{-# language
-        BangPatterns
-      , MagicHash
-      , ScopedTypeVariables
-      , TypeApplications
-      , UnboxedTuples
-  #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE UnboxedTuples #-}
 
 module Main (main) where
 
 import Prelude hiding
-  ( null, read, Foldable(..), map
+  ( Foldable (..)
+  , map
+  , null
+  , read
   )
 
 import Control.Monad
-import Data.Functor.Identity (Identity(..))
-import Data.Monoid (Sum(..))
+import Data.Functor.Identity (Identity (..))
+import Data.Monoid (Sum (..))
 import Data.Primitive.Contiguous
 import GHC.Exts (RealWorld)
 import System.Random
@@ -301,23 +302,31 @@
         func "primArray100" mapMaybeJ primArray100
         func "primArray1000" mapMaybeJ primArray1000
 
-mapMaybeJ :: forall arr. (Contiguous arr, Element arr Int)
-  => arr Int
-  -> ()
+mapMaybeJ ::
+  forall arr.
+  (Contiguous arr, Element arr Int) =>
+  arr Int ->
+  ()
 mapMaybeJ arr =
-  let !(arr' :: arr Int) = mapMaybe Just arr
+  let !(_arr' :: arr Int) = mapMaybe Just arr
    in ()
 
-mapPlus1 :: forall arr. (Contiguous arr, Element arr Int)
-  => arr Int -> ()
-mapPlus1 arr = let !(arr' :: arr Int) = map (+1) arr in ()
+mapPlus1 ::
+  forall arr.
+  (Contiguous arr, Element arr Int) =>
+  arr Int ->
+  ()
+mapPlus1 arr = let !(_arr' :: arr Int) = map (+ 1) arr in ()
 
-mapPlus1' :: forall arr. (Contiguous arr, Element arr Int)
-  => arr Int -> ()
-mapPlus1' arr = let !(arr' :: arr Int) = map' (+1) arr in ()
+mapPlus1' ::
+  forall arr.
+  (Contiguous arr, Element arr Int) =>
+  arr Int ->
+  ()
+mapPlus1' arr = let !(_arr' :: arr Int) = map' (+ 1) arr in ()
 
-plus1 :: Int -> Int
-plus1 = (+1)
+_plus1 :: Int -> Int
+_plus1 = (+ 1)
 
 sum1 :: a -> Sum Int
 sum1 = const (Sum 1)
@@ -335,21 +344,22 @@
 index## ix arr = case index# arr ix of !(# _x #) -> ()
 
 randomList :: Int -> IO [Int]
-randomList sz = replicateM sz (randomRIO (minBound,maxBound))
+randomList sz = replicateM sz (randomRIO (minBound, maxBound))
 
-randomC :: (Contiguous arr, Element arr Int)
-  => Int
-  -> IO (arr Int)
+randomC ::
+  (Contiguous arr, Element arr Int) =>
+  Int ->
+  IO (arr Int)
 randomC sz = do
   rList <- randomList sz
   rList' <- shuffleM rList
   pure (fromListN sz rList')
 
-randomCM :: (Contiguous arr, Element arr Int)
-  => Int
-  -> IO (Mutable arr RealWorld Int)
+randomCM ::
+  (Contiguous arr, Element arr Int) =>
+  Int ->
+  IO (Mutable arr RealWorld Int)
 randomCM sz = do
   rList <- randomList sz
   rList' <- shuffleM rList
   fromListMutableN sz rList'
-
diff --git a/cabal.project b/cabal.project
new file mode 100644
--- /dev/null
+++ b/cabal.project
@@ -0,0 +1,2 @@
+packages: .
+tests: True
diff --git a/contiguous.cabal b/contiguous.cabal
--- a/contiguous.cabal
+++ b/contiguous.cabal
@@ -1,81 +1,87 @@
-cabal-version: 2.0
-name: contiguous
-version: 0.6.4.0
-homepage: https://github.com/andrewthad/contiguous
-bug-reports: https://github.com/andrewthad/contiguous/issues
-author: Andrew Martin
-maintainer: andrew.thaddeus@gmail.com
-copyright: 2018 Andrew Martin
-license: BSD3
-license-file: LICENSE
-build-type: Simple
-extra-source-files: README.md
-synopsis: Unified interface for primitive arrays
-category: Array,Data,Primitive
+cabal-version:      2.4
+name:               contiguous
+version:            0.6.4.1
+homepage:           https://github.com/byteverse/contiguous
+bug-reports:        https://github.com/byteverse/contiguous/issues
+author:             Andrew Martin
+maintainer:         amartin@layer3com.com
+copyright:          2018 Andrew Martin
+license:            BSD-3-Clause
+license-file:       LICENSE
+build-type:         Simple
+extra-doc-files:
+  CHANGELOG.md
+  README.md
+
+extra-source-files: cabal.project
+synopsis:           Unified interface for primitive arrays
+category:           Array,Data,Primitive
 description:
   This package provides a typeclass `Contiguous` that offers a
   unified interface to working with `Array`, `SmallArray`,
   `PrimArray`, and `UnliftedArray`.
 
-source-repository head
-  type: git
-  location: https://github.com/andrewthad/contiguous
+common build-settings
+  default-language: Haskell2010
+  ghc-options:      -Wall -Wunused-packages
 
 library
+  import:          build-settings
   exposed-modules:
     Data.Primitive.Contiguous
     Data.Primitive.Contiguous.Class
-  other-modules:
-    Data.Primitive.Contiguous.Shim
-  hs-source-dirs: src
+
+  other-modules:   Data.Primitive.Contiguous.Shim
+  hs-source-dirs:  src
   build-depends:
-      base >=4.14 && <5
-    , primitive >= 0.7.2 && < 0.10
-    , primitive-unlifted >= 2.1
-    , deepseq >= 1.4
-    , run-st >= 0.1.3.2
-  default-language: Haskell2010
-  ghc-options: -O2 -Wall
+    , base                >=4.14    && <5
+    , deepseq             >=1.4
+    , primitive           >=0.7.2   && <0.10
+    , primitive-unlifted  >=2.1
+    , run-st              >=0.1.3.2
 
+  ghc-options:     -O2
+
 test-suite unit-tests
-  type: exitcode-stdio-1.0
-  main-is: UnitTests.hs
+  import:         build-settings
+  type:           exitcode-stdio-1.0
+  main-is:        UnitTests.hs
   hs-source-dirs: test
   build-depends:
-      base
+    , base
     , contiguous
     , primitive
-    , vector
     , QuickCheck
     , quickcheck-instances
-  default-language: Haskell2010
-  ghc-options: -O2 -Wall
+    , vector
 
 test-suite laws
-  type: exitcode-stdio-1.0
-  main-is: Laws.hs
+  import:         build-settings
+  type:           exitcode-stdio-1.0
+  main-is:        Laws.hs
   hs-source-dirs: test
   build-depends:
-      base
+    , base
     , contiguous
-    , primitive
-    , vector
     , QuickCheck
-    , quickcheck-instances
     , quickcheck-classes
-  default-language: Haskell2010
-  ghc-options: -O2 -Wall
 
+  ghc-options:    -O2
+
 benchmark weigh
-  type: exitcode-stdio-1.0
+  import:         build-settings
+  type:           exitcode-stdio-1.0
   build-depends:
-      base
-    , primitive
+    , base
     , contiguous
-    , weigh
     , random
     , random-shuffle
-  default-language: Haskell2010
+    , weigh
+
   hs-source-dirs: bench
-  main-is: Main.hs
-  ghc-options: -O2
+  main-is:        Main.hs
+  ghc-options:    -O2
+
+source-repository head
+  type:     git
+  location: git://github.com/byteverse/contiguous.git
diff --git a/src/Data/Primitive/Contiguous.hs b/src/Data/Primitive/Contiguous.hs
--- a/src/Data/Primitive/Contiguous.hs
+++ b/src/Data/Primitive/Contiguous.hs
@@ -1,2046 +1,2362 @@
-{-# language BangPatterns #-}
-{-# language FlexibleInstances #-}
-{-# language LambdaCase #-}
-{-# language MagicHash #-}
-{-# language RankNTypes #-}
-{-# language ScopedTypeVariables #-}
-{-# language TypeFamilies #-}
-{-# language TypeFamilyDependencies #-}
-{-# language UnboxedTuples #-}
-
--- | The contiguous package presents a common API to a number of contiguous
--- array types and their mutable counterparts. This is enabled with the
--- 'Contiguous' typeclass, which parameterises over a contiguous array type and
--- defines the core operations. However, the stable part of the interface is
--- contained in this module, which combines those primitives into common,
--- efficient array algorithms suitable for replacing pointer-heavy list
--- manipulations.
-module Data.Primitive.Contiguous
-  (
-    -- * Accessors
-    -- ** Length Information
-    size
-  , sizeMut
-  , null
-    -- ** Indexing
-  , index
-  , index#
-  , read
-    -- ** Monadic indexing
-  , indexM
-
-    -- * Construction
-    -- ** Initialisation
-  , empty
-  , new
-  , singleton
-  , doubleton
-  , tripleton
-  , quadrupleton
-  , quintupleton
-  , sextupleton
-  , replicate
-  , replicateMut
-  , generate
-  , generateM
-  , generateMutable
-  , iterateN
-  , iterateMutableN
-  , write
-    -- ** Fixed Length
-  , construct1
-  , construct2
-  , construct3
-  , construct4
-  , construct5
-  , construct6
-    -- ** Running
-  , run
-    -- ** Monadic initialisation
-  , replicateMutM
-  , generateMutableM
-  , iterateMutableNM
-  , create
-  , createT
-    -- ** Unfolding
-  , unfoldr
-  , unfoldrN
-  , unfoldrMutable
-    -- ** Enumeration
-  , enumFromN
-  , enumFromMutableN
-    -- ** Concatenation
-  , append
-    -- ** Splitting and Splicing
-  , insertAt
-
-    -- * Slicing
-  , Slice
-  , MutableSlice
-  , slice
-  , sliceMut
-  , toSlice
-  , toSliceMut
-
-    -- * Modifying arrays
-  , replaceAt
-  , modifyAt
-  , modifyAt'
-  , modifyAtF
-  , modifyAtF'
-  , deleteAt
-    -- ** Permutations
-  , reverse
-  , reverseMutable
-  , reverseSlice
-
-    -- ** Resizing
-  , resize
-  , shrink
-  , unsafeShrinkAndFreeze
-
-    -- * Elementwise operations
-    -- ** Mapping
-  , map
-  , map'
-  , mapMutable
-  , mapMutable'
-  , imap
-  , imap'
-  , imapMutable
-  , imapMutable'
-  , modify
-  , modify'
-  , mapMaybe
-
-    -- ** Zipping
-  , zip
-  , zipWith
-  , izipWith
-
-    -- ** Specific elements
-  , swap
-
-    -- * Working with predicates
-    -- ** Filtering
-  , filter
-  , ifilter
-  , catMaybes
-  , lefts
-  , rights
-  , partitionEithers
-    -- ** Searching
-  , find
-  , findIndex
-  , elem
-  , maximum
-  , minimum
-  , maximumBy
-  , minimumBy
-    -- ** Comparing for equality
-  , equals
-  , equalsMut
-  , same
-
-    -- * Folds
-  , foldl
-  , foldl'
-  , foldr
-  , foldr'
-  , foldMap
-  , foldMap'
-  , foldlMap'
-  , ifoldl'
-  , ifoldr
-  , ifoldr'
-  , ifoldlMap'
-  , ifoldlMap1'
-  , foldlM'
-  , ifoldlM'
-  , foldrM'
-  , asum
-  , all
-  , any
-    -- ** Zipping Folds
-  , foldrZipWith
-  , ifoldrZipWith
-  , foldlZipWith'
-  , ifoldlZipWith'
-  , foldlZipWithM'
-  , ifoldlZipWithM'
-
-    -- * Traversals
-  , traverse
-  , traverse_
-  , itraverse
-  , itraverse_
-  , traverseP
-  , itraverseP
-  , mapM
-  , forM
-  , mapM_
-  , forM_
-  , for
-  , for_
-  , sequence
-  , sequence_
-
-    -- * Typeclass method defaults
-  , (<$)
-  , ap
-
-    -- * Prefix sums (scans)
-  , scanl
-  , scanl'
-  , iscanl
-  , iscanl'
-  , prescanl
-  , prescanl'
-  , iprescanl
-  , iprescanl'
-  --, postscanl
-  --, ipostscanl
-
-  , mapAccum'
-  , mapAccumLM'
-
-    -- * Conversions
-    -- ** Lists
-  , fromList
-  , fromListN
-  , fromListMutable
-  , fromListMutableN
-  , unsafeFromListN
-  , unsafeFromListReverseN
-  , unsafeFromListReverseMutableN
-  , toList
-  , toListMutable
-    -- ** Other array types
-  , convert
-  , lift
-  , liftMut
-  , unlift
-  , unliftMut
-    -- ** Between mutable and immutable variants
-  , clone
-  , cloneMut
-  , copy
-  , copyMut
-  , freeze
-  , thaw
-  , unsafeFreeze
-
-    -- * Hashing
-  , liftHashWithSalt
-
-    -- * Forcing an array and its contents
-  , rnf
-
-    -- * Classes
-  , Contiguous(Mutable,Element,Sliced,MutableSliced)
-  , ContiguousU
-  , Always
-
-    -- * Re-Exports
-  , Array
-  , MutableArray
-  , SmallArray
-  , SmallMutableArray
-  , PrimArray
-  , MutablePrimArray
-  , UnliftedArray
-  , MutableUnliftedArray
-  ) where
-
-import Control.Monad.Primitive
-import Data.Primitive hiding (fromList,fromListN)
-import Data.Primitive.Unlifted.Array
-import Prelude hiding (Foldable(..),map,all,any,traverse,read,filter,replicate,reverse,zip,zipWith,scanl,(<$),mapM,mapM_,sequence,sequence_)
-
-import Control.Applicative (liftA2)
-import Control.Monad (when)
-import Control.Monad.ST (runST,ST)
-import Data.Bits (xor)
-import Data.Coerce (coerce)
-import Data.Foldable (length)
-import Data.Primitive.Contiguous.Class (Contiguous(..), ContiguousU(..), Slice, MutableSlice, Always)
-import Data.Semigroup (First(..))
-import Data.Word (Word8)
-import GHC.Base (build)
-import GHC.Exts (MutableArrayArray#,unsafeCoerce#,sameMutableArrayArray#,isTrue#,dataToTag#,Int(..))
-
-import qualified Control.Applicative as A
-import qualified Prelude
-
-construct1 :: (Contiguous arr, Element arr a)
-  => a -> arr a
-{-# inline construct1 #-}
-construct1 = singleton
-
-construct2 :: (Contiguous arr, Element arr a)
-  => a -> a -> arr a
-{-# inline construct2 #-}
-construct2 = doubleton
-
-construct3 :: (Contiguous arr, Element arr a)
-  => a -> a -> a -> arr a
-{-# inline construct3 #-}
-construct3 = tripleton
-
-construct4 :: (Contiguous arr, Element arr a)
-  => a -> a -> a -> a -> arr a
-{-# inline construct4 #-}
-construct4 = quadrupleton
-
-construct5 :: (Contiguous arr, Element arr a)
-  => a -> a -> a -> a -> a -> arr a
-{-# inline construct5 #-}
-construct5 = quintupleton
-
-construct6 :: (Contiguous arr, Element arr a)
-  => a -> a -> a -> a -> a -> a -> arr a
-{-# inline construct6 #-}
-construct6 = sextupleton
-
--- | Append two arrays.
-append :: (Contiguous arr, Element arr a) => arr a -> arr a -> arr a
-append !a !b = run $ do
-  m <- new (size a + size b)
-  copy m 0 (toSlice a)
-  copy m (size a) (toSlice b)
-  unsafeFreeze m
-{-# inline append #-}
-
--- | Delete the element at the given position.
-deleteAt :: (Contiguous arr, Element arr a) => arr a -> Int -> arr a
-deleteAt src i = run $ do
-  dst <- thaw (slice src 0 (size src - 1))
-  let !i' = i + 1
-  copy dst i (slice src i' (size src - i'))
-  unsafeFreeze dst
-{-# inline deleteAt #-}
-
--- | Create a copy of an array except the element at the index is replaced with
---   the given value.
-replaceAt :: (Contiguous arr, Element arr a) => arr a -> Int -> a -> arr a
-replaceAt src i x = create $ do
-  dst <- thaw (toSlice src)
-  write dst i x
-  pure dst
-{-# inline replaceAt #-}
-
-modifyAt :: (Contiguous arr, Element arr a)
-  => (a -> a) -> arr a -> Int -> arr a
-modifyAt f src i = replaceAt src i $ f (index src i)
-{-# inline modifyAt #-}
-
--- | Variant of modifyAt that forces the result before installing it in the
--- array.
-modifyAt' :: (Contiguous arr, Element arr a)
-  => (a -> a) -> arr a -> Int -> arr a
-modifyAt' f src i = replaceAt src i $! f (index src i)
-{-# inline modifyAt' #-}
-
-modifyAtF :: (Contiguous arr, Element arr a, Functor f)
-  => (a -> f a) -> arr a -> Int -> f (arr a)
-modifyAtF f src i = replaceAt src i <$> f (index src i)
-{-# inline modifyAtF #-}
-
--- | Variant of modifyAtF that forces the result before installing it in the
--- array. Note that this requires 'Monad' rather than 'Functor'.
-modifyAtF' :: (Contiguous arr, Element arr a, Monad f)
-  => (a -> f a) -> arr a -> Int -> f (arr a)
-modifyAtF' f src i = do
-  !r <- f (index src i)
-  let !dst = replaceAt src i r
-  pure dst
-{-# inline modifyAtF' #-}
-
--- | Map over the elements of an array with the index.
-imap :: (Contiguous arr1, Element arr1 b, Contiguous arr2, Element arr2 c)
-  => (Int -> b -> c) -> arr1 b -> arr2 c
-imap f a = run $ do
-  mb <- new (size a)
-  let go !i
-        | i == size a = pure ()
-        | otherwise = do
-            x <- indexM a i
-            write mb i (f i x)
-            go (i+1)
-  go 0
-  unsafeFreeze mb
-{-# inline imap #-}
-
--- | Map strictly over the elements of an array with the index.
---
---   Note that because a new array must be created, the resulting
---   array type can be /different/ than the original.
-imap' :: (Contiguous arr1, Element arr1 b, Contiguous arr2, Element arr2 c)
-  => (Int -> b -> c) -> arr1 b -> arr2 c
-imap' f a = run $ do
-  mb <- new (size a)
-  let go !i
-        | i == size a = pure ()
-        | otherwise = do
-            x <- indexM a i
-            let !b = f i x
-            write mb i b
-            go (i + 1)
-  go 0
-  unsafeFreeze mb
-{-# inline imap' #-}
-
--- | Map over the elements of an array.
---
---   Note that because a new array must be created, the resulting
---   array type can be /different/ than the original.
-map :: (Contiguous arr1, Element arr1 b, Contiguous arr2, Element arr2 c)
-  => (b -> c) -> arr1 b -> arr2 c
-map f a = run $ do
-  mb <- new (size a)
-  let go !i
-        | i == size a = pure ()
-        | otherwise = do
-            x <- indexM a i
-            write mb i (f x)
-            go (i+1)
-  go 0
-  unsafeFreeze mb
-{-# inline map #-}
-
--- | Map strictly over the elements of an array.
---
---   Note that because a new array must be created, the resulting
---   array type can be /different/ than the original.
-map' :: (Contiguous arr1, Element arr1 b, Contiguous arr2, Element arr2 c)
-  => (b -> c) -> arr1 b -> arr2 c
-map' f a = run $ do
-  mb <- new (size a)
-  let go !i
-        | i == size a = pure ()
-        | otherwise = do
-            x <- indexM a i
-            let !b = f x
-            write mb i b
-            go (i+1)
-  go 0
-  unsafeFreeze mb
-{-# inline map' #-}
-
--- | Convert one type of array into another.
-convert :: (Contiguous arr1, Element arr1 b, Contiguous arr2, Element arr2 b)
-  => arr1 b -> arr2 b
-convert a = map id a
-{-# inline convert #-}
-
--- | Right fold over the element of an array.
-foldr :: (Contiguous arr, Element arr a) => (a -> b -> b) -> b -> arr a -> b
-{-# inline foldr #-}
-foldr f z = \arr ->
-  let !sz = size arr
-      go !ix = if sz > ix
-        then case index# arr ix of
-          (# x #) -> f x (go (ix + 1))
-        else z
-  in go 0
-
--- | Right fold over the element of an array, lazy in the accumulator,
--- provides index to the step function.
-ifoldr :: (Contiguous arr, Element arr a) => (Int -> a -> b -> b) -> b -> arr a -> b
-{-# inline ifoldr #-}
-ifoldr f z = \arr ->
-  let !sz = size arr
-      go !ix = if sz > ix
-        then case index# arr ix of
-          (# x #) -> f ix x (go (ix + 1))
-        else z
-  in go 0
-
--- | Strict right fold over the elements of an array.
-foldr' :: (Contiguous arr, Element arr a) => (a -> b -> b) -> b -> arr a -> b
-foldr' f !z = \arr ->
-  let go !ix !acc = if ix == -1
-        then acc
-        else case index# arr ix of
-          (# x #) -> go (ix - 1) (f x acc)
-  in go (size arr - 1) z
-{-# inline foldr' #-}
-
--- | Left fold over the elements of an array.
-foldl :: (Contiguous arr, Element arr a) => (b -> a -> b) -> b -> arr a -> b
-foldl f z = \arr ->
-  let !sz = size arr
-      go !ix acc = if ix == sz
-        then acc
-        else case index# arr ix of
-          (# x #) -> go (ix + 1) (f acc x)
-  in go 0 z
-{-# inline foldl #-}
-
--- | Strict left fold over the elements of an array.
-foldl' :: (Contiguous arr, Element arr a) => (b -> a -> b) -> b -> arr a -> b
-foldl' f !z = \arr ->
-  let !sz = size arr
-      go !ix !acc = if ix == sz
-        then acc
-        else case index# arr ix of
-          (# x #) -> go (ix + 1) (f acc x)
-  in go 0 z
-{-# inline foldl' #-}
-
--- | Strict left fold over the elements of an array, where the accumulating
---   function cares about the index of the element.
-ifoldl' :: (Contiguous arr, Element arr a)
-  => (b -> Int -> a -> b) -> b -> arr a -> b
-ifoldl' f !z = \arr ->
-  let !sz = size arr
-      go !ix !acc = if ix == sz
-        then acc
-        else case index# arr ix of
-          (# x #) -> go (ix + 1) (f acc ix x)
-  in go 0 z
-{-# inline ifoldl' #-}
-
--- | Strict right fold over the elements of an array, where the accumulating
---   function cares about the index of the element.
-ifoldr' :: (Contiguous arr, Element arr a)
-  => (Int -> a -> b -> b) -> b -> arr a -> b
-ifoldr' f !z = \arr ->
-  let !sz = size arr
-      go !ix !acc = if ix == (-1)
-        then acc
-        else case index# arr ix of
-          (# x #) -> go (ix - 1) (f ix x acc)
-  in go (sz - 1) z
-{-# inline ifoldr' #-}
-
--- | Monoidal fold over the element of an array.
-foldMap :: (Contiguous arr, Element arr a, Monoid m) => (a -> m) -> arr a -> m
-foldMap f = \arr ->
-  let !sz = size arr
-      go !ix = if sz > ix
-        then case index# arr ix of
-          (# x #) -> mappend (f x) (go (ix + 1))
-        else mempty
-  in go 0
-{-# inline foldMap #-}
-
--- | Strict monoidal fold over the elements of an array.
-foldMap' :: (Contiguous arr, Element arr a, Monoid m)
-  => (a -> m) -> arr a -> m
-foldMap' f = \arr ->
-  let !sz = size arr
-      go !ix !acc = if ix == sz
-        then acc
-        else case index# arr ix
-          of (# x #) -> go (ix + 1) (mappend acc (f x))
-  in go 0 mempty
-{-# inline foldMap' #-}
-
--- | Strict left monoidal fold over the elements of an array.
-foldlMap' :: (Contiguous arr, Element arr a, Monoid m)
-  => (a -> m) -> arr a -> m
-foldlMap' = foldMap'
-{-# inline foldlMap' #-}
-
--- | Strict monoidal fold over the elements of an array.
-ifoldlMap' :: (Contiguous arr, Element arr a, Monoid m)
-  => (Int -> a -> m)
-  -> arr a
-  -> m
-ifoldlMap' f = \arr ->
-  let !sz = size arr
-      go !ix !acc = if ix == sz
-        then acc
-        else case index# arr ix of
-          (# x #) -> go (ix + 1) (mappend acc (f ix x))
-  in go 0 mempty
-{-# inline ifoldlMap' #-}
-
--- | Strict monoidal fold over the elements of an array.
-ifoldlMap1' :: (Contiguous arr, Element arr a, Semigroup m)
-  => (Int -> a -> m)
-  -> arr a
-  -> m
-ifoldlMap1' f = \arr ->
-  let !sz = size arr
-      go !ix !acc = if ix == sz
-        then acc
-        else case index# arr ix of
-          (# x #) -> go (ix + 1) (acc <> f ix x)
-      !(# e0 #) = index# arr 0
-  in go 1 (f 0 e0)
-{-# inline ifoldlMap1' #-}
-
--- | Strict right monadic fold over the elements of an array.
-foldrM' :: (Contiguous arr, Element arr a, Monad m)
-  => (a -> b -> m b) -> b -> arr a -> m b
-foldrM' f !z0 = \arr ->
-  let !sz = size arr
-      go !ix !acc1 = if ix >= 0
-        then do
-          let (# x #) = index# arr ix
-          acc2 <- f x acc1
-          go (ix - 1) acc2
-        else pure acc1
-  in go (sz - 1) z0
-{-# inline foldrM' #-}
-
--- | Strict left monadic fold over the elements of an array.
-foldlM' :: (Contiguous arr, Element arr a, Monad m)
-  => (b -> a -> m b) -> b -> arr a -> m b
-foldlM' f !z0 = \arr ->
-  let !sz = size arr
-      go !ix !acc1 = if ix < sz
-        then do
-          let (# x #) = index# arr ix
-          acc2 <- f acc1 x
-          go (ix + 1) acc2
-        else pure acc1
-  in go 0 z0
-{-# inline foldlM' #-}
-
--- | Strict left monadic fold over the elements of an array.
-ifoldlM' :: (Contiguous arr, Element arr a, Monad m)
-  => (b -> Int -> a -> m b) -> b -> arr a -> m b
-ifoldlM' f z0 = \arr ->
-  let !sz = size arr
-      go !ix !acc1 = if ix < sz
-        then do
-          let (# x #) = index# arr ix
-          acc2 <- f acc1 ix x
-          go (ix + 1) acc2
-        else pure acc1
-  in go 0 z0
-{-# inline ifoldlM' #-}
-
--- | Drop elements that do not satisfy the predicate.
-filter :: (Contiguous arr, Element arr a)
-  => (a -> Bool)
-  -> arr a
-  -> arr a
-filter p arr = ifilter (const p) arr
-{-# inline filter #-}
-
--- | Drop elements that do not satisfy the predicate which
---   is applied to values and their indices.
-ifilter :: (Contiguous arr, Element arr a)
-  => (Int -> a -> Bool)
-  -> arr a
-  -> arr a
-ifilter p arr = run $ do
-  marr :: MutablePrimArray s Word8 <- newPrimArray sz
-  let go1 :: Int -> Int -> ST s Int
-      go1 !ix !numTrue = if ix < sz
-        then do
-          atIx <- indexM arr ix
-          let !keep = p ix atIx
-          let !keepTag = I# (dataToTag# keep)
-          writePrimArray marr ix (fromIntegral keepTag)
-          go1 (ix + 1) (numTrue + keepTag)
-        else pure numTrue
-  numTrue <- go1 0 0
-  if numTrue == sz
-    then pure arr
-    else do
-      marrTrues <- new numTrue
-      let go2 !ixSrc !ixDst = when (ixDst < numTrue) $ do
-            atIxKeep <- readPrimArray marr ixSrc
-            if isTrue atIxKeep
-              then do
-                atIxVal <- indexM arr ixSrc
-                write marrTrues ixDst atIxVal
-                go2 (ixSrc + 1) (ixDst + 1)
-              else go2 (ixSrc + 1) ixDst
-      go2 0 0
-      unsafeFreeze marrTrues
-  where
-    !sz = size arr
-{-# inline ifilter #-}
-
--- | The 'mapMaybe' function is a version of 'map' which can throw out elements.
---   In particular, the functional arguments returns something of type @'Maybe' b@.
---   If this is 'Nothing', no element is added on to the result array. If it is
---   @'Just' b@, then @b@ is included in the result array.
-mapMaybe :: forall arr1 arr2 a b.
-     ( Contiguous arr1, Element arr1 a
-     , Contiguous arr2, Element arr2 b
-     )
-  => (a -> Maybe b)
-  -> arr1 a
-  -> arr2 b
-mapMaybe f arr = run $ do
-  let !sz = size arr
-  let go :: Int -> Int -> [b] -> ST s ([b],Int)
-      go !ix !numJusts !justs = if ix < sz
-        then do
-          atIx <- indexM arr ix
-          case f atIx of
-            Nothing -> go (ix+1) numJusts justs
-            Just x -> go (ix+1) (numJusts+1) (x:justs)
-        else pure (justs,numJusts)
-  !(bs,!numJusts) <- go 0 0 []
-  !marr <- unsafeFromListReverseMutableN numJusts bs
-  unsafeFreeze marr
-{-# inline mapMaybe #-}
-
-{-# inline isTrue #-}
-isTrue :: Word8 -> Bool
-isTrue 0 = False
-isTrue _ = True
-
--- | The 'catMaybes' function takes a list of 'Maybe's and returns a
---   list of all the 'Just' values.
-catMaybes :: (Contiguous arr, Element arr a, Element arr (Maybe a))
-  => arr (Maybe a)
-  -> arr a
-catMaybes = mapMaybe id
-{-# inline catMaybes #-}
-
--- | @'replicate' n x@ is an array of length @n@ with @x@ the value of every element.
-replicate :: (Contiguous arr, Element arr a) => Int -> a -> arr a
-replicate n x = create (replicateMut n x)
-{-# inline replicate #-}
-
--- | @'replicateMutM' n act@ performs the action n times, gathering the results.
-replicateMutM :: (PrimMonad m, Contiguous arr, Element arr a)
-  => Int
-  -> m a
-  -> m (Mutable arr (PrimState m) a)
-replicateMutM len act = do
-  marr <- new len
-  let go !ix = when (ix < len) $ do
-        x <- act
-        write marr ix x
-        go (ix + 1)
-  go 0
-  pure marr
-{-# inline replicateMutM #-}
-
-
--- | Create an array from a list. If the given length does
--- not match the actual length, this function has undefined
--- behavior.
-unsafeFromListN :: (Contiguous arr, Element arr a)
-  => Int -- ^ length of list
-  -> [a] -- ^ list
-  -> arr a
-unsafeFromListN n l = create (unsafeFromListMutableN n l)
-{-# inline unsafeFromListN #-}
-
-unsafeFromListMutableN :: (Contiguous arr, Element arr a, PrimMonad m)
-  => Int
-  -> [a]
-  -> m (Mutable arr (PrimState m) a)
-unsafeFromListMutableN n l = do
-  m <- new n
-  let go !_ [] = pure m
-      go !ix (x : xs) = do
-        write m ix x
-        go (ix+1) xs
-  go 0 l
-{-# inline unsafeFromListMutableN #-}
-
--- | Create a mutable array from a list, reversing the order of
---   the elements. If the given length does not match the actual length,
---   this function has undefined behavior.
-unsafeFromListReverseMutableN :: (Contiguous arr, Element arr a, PrimMonad m)
-  => Int
-  -> [a]
-  -> m (Mutable arr (PrimState m) a)
-unsafeFromListReverseMutableN n l = do
-  m <- new n
-  let go !_ [] = pure m
-      go !ix (x : xs) = do
-        write m ix x
-        go (ix-1) xs
-  go (n - 1) l
-{-# inline unsafeFromListReverseMutableN #-}
-
--- | Create an array from a list, reversing the order of the
--- elements. If the given length does not match the actual length,
--- this function has undefined behavior.
-unsafeFromListReverseN :: (Contiguous arr, Element arr a)
-  => Int
-  -> [a]
-  -> arr a
-unsafeFromListReverseN n l = create (unsafeFromListReverseMutableN n l)
-{-# inline unsafeFromListReverseN #-}
-
--- | Map over a mutable array, modifying the elements in place.
-mapMutable :: (Contiguous arr, Element arr a, PrimMonad m)
-  => (a -> a)
-  -> Mutable arr (PrimState m) a
-  -> m ()
-mapMutable f !marr = do
-  !sz <- sizeMut marr
-  let go !ix = when (ix < sz) $ do
-        a <- read marr ix
-        write marr ix (f a)
-        go (ix + 1)
-  go 0
-{-# inline mapMutable #-}
-
--- | Strictly map over a mutable array, modifying the elements in place.
-mapMutable' :: (PrimMonad m, Contiguous arr, Element arr a)
-  => (a -> a)
-  -> Mutable arr (PrimState m) a
-  -> m ()
-mapMutable' f !marr = do
-  !sz <- sizeMut marr
-  let go !ix = when (ix < sz) $ do
-        a <- read marr ix
-        let !b = f a
-        write marr ix b
-        go (ix + 1)
-  go 0
-{-# inline mapMutable' #-}
-
--- | Map over a mutable array with indices, modifying the elements in place.
-imapMutable :: (Contiguous arr, Element arr a, PrimMonad m)
-  => (Int -> a -> a)
-  -> Mutable arr (PrimState m) a
-  -> m ()
-imapMutable f !marr = do
-  !sz <- sizeMut marr
-  let go !ix = when (ix < sz) $ do
-        a <- read marr ix
-        write marr ix (f ix a)
-        go (ix + 1)
-  go 0
-{-# inline imapMutable #-}
-
--- | Strictly map over a mutable array with indices, modifying the elements in place.
-imapMutable' :: (PrimMonad m, Contiguous arr, Element arr a)
-  => (Int -> a -> a)
-  -> Mutable arr (PrimState m) a
-  -> m ()
-imapMutable' f !marr = do
-  !sz <- sizeMut marr
-  let go !ix = when (ix < sz) $ do
-        a <- read marr ix
-        let !b = f ix a
-        write marr ix b
-        go (ix + 1)
-  go 0
-{-# inline imapMutable' #-}
-
--- | Map each element of the array to an action, evaluate these
---   actions from left to right, and collect the results in a
---   new array.
-traverseP ::
-     ( PrimMonad m
-     , Contiguous arr1, Element arr1 a
-     , Contiguous arr2, Element arr2 b
-     )
-  => (a -> m b)
-  -> arr1 a
-  -> m (arr2 b)
-traverseP f !arr = do
-  let !sz = size arr
-  !marr <- new sz
-  let go !ix = when (ix < sz) $ do
-        a <- indexM arr ix
-        b <- f a
-        write marr ix b
-        go (ix + 1)
-  go 0
-  unsafeFreeze marr
-{-# inline traverseP #-}
-
--- | Map each element of the array to an action, evaluate these
---   actions from left to right, and collect the results in a
---   new array.
-itraverseP ::
-     ( PrimMonad m
-     , Contiguous arr1, Element arr1 a
-     , Contiguous arr2, Element arr2 b
-     )
-  => (Int -> a -> m b)
-  -> arr1 a
-  -> m (arr2 b)
-itraverseP f !arr = do
-  let !sz = size arr
-  !marr <- new sz
-  let go !ix = when (ix < sz) $ do
-        a <- indexM arr ix
-        b <- f ix a
-        write marr ix b
-        go (ix + 1)
-  go 0
-  unsafeFreeze marr
-{-# inline itraverseP #-}
-
-newtype STA v a = STA {_runSTA :: forall s. Mutable v s a -> ST s (v a)}
-
-runSTA :: (Contiguous v, Element v a) => Int -> STA v a -> v a
-runSTA !sz (STA m) = runST $ new sz >>= m
-{-# inline runSTA #-}
-
--- | Map each element of the array to an action, evaluate these
---   actions from left to right, and collect the results.
---   For a version that ignores the results, see 'traverse_'.
-traverse ::
-  ( Contiguous arr1
-  , Contiguous arr2
-  , Element arr1 a
-  , Element arr2 b
-  , Applicative f
-  )
-  => (a -> f b)
-  -> arr1 a
-  -> f (arr2 b)
-traverse f = itraverse (const f)
-{-# inline traverse #-}
-
--- | Map each element of the array to an action, evaluate these
---   actions from left to right, and ignore the results.
---   For a version that doesn't ignore the results, see 'traverse'.
-traverse_ ::
-     (Contiguous arr, Element arr a, Applicative f)
-  => (a -> f b)
-  -> arr a
-  -> f ()
-traverse_ f = itraverse_ (const f)
-
--- | Map each element of the array and its index to an action,
---   evaluating these actions from left to right.
-itraverse ::
-  ( Contiguous arr1
-  , Contiguous arr2
-  , Element arr1 a
-  , Element arr2 b
-  , Applicative f
-  )
-  => (Int -> a -> f b)
-  -> arr1 a
-  -> f (arr2 b)
-itraverse f = \arr ->
-  let !sz = size arr
-      go !ix = if ix == sz
-        then pure (STA unsafeFreeze)
-        else case index# arr ix of
-          (# x #) -> liftA2
-            (\b (STA m) -> STA $ \marr -> do
-              write marr ix b
-              m marr
-            )
-            (f ix x)
-            (go (ix + 1))
-  in if sz == 0
-    then pure empty
-    else runSTA sz <$> go 0
-{-# inline itraverse #-}
-
--- | Map each element of the array and its index to an action,
---   evaluate these actions from left to right, and ignore the results.
---   For a version that doesn't ignore the results, see 'itraverse'.
-itraverse_ ::
-     (Contiguous arr, Element arr a, Applicative f)
-  => (Int -> a -> f b)
-  -> arr a
-  -> f ()
-itraverse_ f = \arr ->
-  let !sz = size arr
-      go !ix = when (ix < sz) $
-        f ix (index arr ix) *> go (ix + 1)
-  in go 0
-{-# inline itraverse_ #-}
-
--- | 'for' is 'traverse' with its arguments flipped. For a version
---   that ignores the results see 'for_'.
-for ::
-  ( Contiguous arr1
-  , Contiguous arr2
-  , Element arr1 a
-  , Element arr2 b
-  , Applicative f
-  )
-  => arr1 a
-  -> (a -> f b)
-  -> f (arr2 b)
-for = flip traverse
-{-# inline for #-}
-
--- | 'for_' is 'traverse_' with its arguments flipped. For a version
---   that doesn't ignore the results see 'for'.
---
---   >>> for_ (C.fromList [1..4] :: PrimArray Int) print
---   1
---   2
---   3
---   4
-for_ :: (Contiguous arr, Element arr a, Applicative f)
-  => arr a
-  -> (a -> f b)
-  -> f ()
-for_ = flip traverse_
-{-# inline for_ #-}
-
--- | Monadic accumulating strict left fold over the elements on an
--- array.
-mapAccumLM' ::
-  ( Contiguous arr1
-  , Contiguous arr2
-  , Element arr1 b
-  , Element arr2 c
-  , Monad m
-  ) => (a -> b -> m (a, c)) -> a -> arr1 b -> m (a, arr2 c)
-{-# inline mapAccumLM' #-}
-mapAccumLM' f a0 src = go 0 [] a0 where
-  !sz = size src
-  go !ix !xs !acc = if ix < sz
-    then do
-      (!acc',!x) <- f acc (index src ix)
-      go (ix + 1) (x : xs) acc'
-    else
-      let !xs' = unsafeFromListReverseN sz xs
-       in pure (acc,xs')
-
-mapAccum' :: forall arr1 arr2 a b c.
-  ( Contiguous arr1
-  , Contiguous arr2
-  , Element arr1 b
-  , Element arr2 c
-  , Monoid a
-  ) => (b -> (a, c)) -> arr1 b -> (a, arr2 c)
-{-# inline mapAccum' #-}
-mapAccum' f !src = runST $ do
-  dst <- new sz
-  acc <- go 0 dst mempty
-  dst' <- unsafeFreeze dst
-  pure (acc,dst')
-  where
-  !sz = size src
-  go :: Int -> Mutable arr2 s c -> a -> ST s a
-  go !ix !dst !accA = if ix < sz
-    then do
-      let (!accB,!x) = f (index src ix)
-      write dst ix x
-      go (ix + 1) dst (accA <> accB)
-    else pure accA
-
--- | Map each element of a structure to a monadic action,
---   evaluate these actions from left to right, and collect
---   the results. for a version that ignores the results see
---   'mapM_'.
-mapM ::
-  ( Contiguous arr1
-  , Contiguous arr2
-  , Element arr1 a
-  , Element arr2 b
-  , Monad m
-  ) => (a -> m b)
-    -> arr1 a
-    -> m (arr2 b)
-mapM f arr =
-  let !sz = size arr
-  in generateM sz $ \ix -> indexM arr ix >>= f
-{-# inline mapM #-}
-
--- | Map each element of a structure to a monadic action,
---   evaluate these actions from left to right, and ignore
---   the results. For a version that doesn't ignore the results
---   see 'mapM'.
---
---   'mapM_' = 'traverse_'
-mapM_ :: (Contiguous arr, Element arr a, Element arr b, Applicative f)
-  => (a -> f b)
-  -> arr a
-  -> f ()
-mapM_ = traverse_
-{-# inline mapM_ #-}
-
--- | 'forM' is 'mapM' with its arguments flipped. For a version that
---   ignores its results, see 'forM_'.
-forM ::
-  ( Contiguous arr1
-  , Contiguous arr2
-  , Element arr1 a
-  , Element arr2 b
-  , Monad m
-  ) => arr1 a
-    -> (a -> m b)
-    -> m (arr2 b)
-forM = flip mapM
-{-# inline forM #-}
-
--- | 'forM_' is 'mapM_' with its arguments flipped. For a version that
---   doesn't ignore its results, see 'forM'.
-forM_ :: (Contiguous arr, Element arr a, Element arr b, Applicative f)
-  => arr a
-  -> (a -> f b)
-  -> f ()
-forM_ = flip traverse_
-{-# inline forM_ #-}
-
--- | Evaluate each action in the structure from left to right
---   and collect the results. For a version that ignores the
---   results see 'sequence_'.
-sequence ::
-  ( Contiguous arr1
-  , Contiguous arr2
-  , Element arr1 (f a)
-  , Element arr2 a
-  , Applicative f
-  ) => arr1 (f a) -> f (arr2 a)
-sequence = traverse id
-{-# inline sequence #-}
-
--- | Evaluate each action in the structure from left to right
---   and ignore the results. For a version that doesn't ignore
---   the results see 'sequence'.
-sequence_ ::
-  ( Contiguous arr
-  , Element arr (f a)
-  , Applicative f
-  ) => arr (f a) -> f ()
-sequence_ = foldr (*>) (pure ())
-{-# inline sequence_ #-}
-
--- | The sum of a collection of actions, generalizing 'concat'.
---
---   >>> asum (C.fromList ['Just' "Hello", 'Nothing', Just "World"] :: Array String)
---   Just "Hello"
-asum ::
-  ( Contiguous arr
-  , Element arr (f a)
-  , A.Alternative f
-  ) => arr (f a) -> f a
-asum = foldr (A.<|>) A.empty
-{-# inline asum #-}
-
--- | Construct an array of the given length by applying
---   the function to each index.
-generate :: (Contiguous arr, Element arr a)
-  => Int
-  -> (Int -> a)
-  -> arr a
-generate len f = create (generateMutable len f)
-{-# inline generate #-}
-
--- | Construct an array of the given length by applying
---   the monadic action to each index.
-generateM :: (Contiguous arr, Element arr a, Monad m)
-  => Int
-  -> (Int -> m a)
-  -> m (arr a)
-{-# inline generateM #-}
-generateM !sz f =
-  let go !ix = if ix < sz
-        then liftA2
-          (\b (STA m) -> STA $ \marr -> do
-              write marr ix b
-              m marr
-          )
-          (f ix)
-          (go (ix + 1))
-        else pure $ STA unsafeFreeze
-  in if sz == 0
-    then pure empty
-    else runSTA sz <$> go 0
-
--- | Construct a mutable array of the given length by applying
---   the function to each index.
-generateMutable :: (Contiguous arr, Element arr a, PrimMonad m)
-  => Int
-  -> (Int -> a)
-  -> m (Mutable arr (PrimState m) a)
-generateMutable len f = generateMutableM len (pure . f)
-{-# inline generateMutable #-}
-
--- | Construct a mutable array of the given length by applying
---   the monadic action to each index.
-generateMutableM :: (Contiguous arr, Element arr a, PrimMonad m)
-  => Int
-  -> (Int -> m a)
-  -> m (Mutable arr (PrimState m) a)
-generateMutableM !len f = do
-  marr <- new len
-  let go !ix = when (ix < len) $ do
-        x <- f ix
-        write marr ix x
-        go (ix + 1)
-  go 0
-  pure marr
-{-# inline generateMutableM #-}
-
--- | Apply a function @n@ times to a value and construct an array
---   where each consecutive element is the result of an additional
---   application of this function. The zeroth element is the original value.
---
---   @'iterateN' 5 ('+' 1) 0 = 'fromListN' 5 [0,1,2,3,4]@
-iterateN :: (Contiguous arr, Element arr a)
-  => Int
-  -> (a -> a)
-  -> a
-  -> arr a
-iterateN len f z0 = runST (iterateMutableN len f z0 >>= unsafeFreeze)
-{-# inline iterateN #-}
-
--- | Apply a function @n@ times to a value and construct a mutable array
---   where each consecutive element is the result of an additional
---   application of this function. The zeroth element is the original value.
-iterateMutableN :: (Contiguous arr, Element arr a, PrimMonad m)
-  => Int
-  -> (a -> a)
-  -> a
-  -> m (Mutable arr (PrimState m) a)
-iterateMutableN len f z0 = iterateMutableNM len (pure . f) z0
-{-# inline iterateMutableN #-}
-
--- | Apply a monadic function @n@ times to a value and construct a mutable array
---   where each consecutive element is the result of an additional
---   application of this function. The zeroth element is the original value.
-iterateMutableNM :: (Contiguous arr, Element arr a, PrimMonad m)
-  => Int
-  -> (a -> m a)
-  -> a
-  -> m (Mutable arr (PrimState m) a)
-iterateMutableNM !len f z0 = do
-  marr <- new len
-  -- we are strict in the accumulator because
-  -- otherwise we could build up a ton of `f (f (f (f .. (f a))))`
-  -- thunks for no reason.
-  let go !ix !acc
-        | ix <= 0 = write marr ix z0 >> go (ix + 1) z0
-        | ix == len = pure ()
-        | otherwise = do
-            a <- f acc
-            write marr ix a
-            go (ix + 1) a
-  go 0 z0
-  pure marr
-{-# inline iterateMutableNM #-}
-
--- | Execute the monad action and freeze the resulting array.
-create :: (Contiguous arr, Element arr a)
-  => (forall s. ST s (Mutable arr s a))
-  -> arr a
-create x = run (unsafeFreeze =<< x)
-{-# inline create #-}
-
--- | Execute the monadic action and freeze the resulting array.
-createT :: (Contiguous arr, Element arr a, Traversable f)
-  => (forall s. ST s (f (Mutable arr s a)))
-  -> f (arr a)
-createT p = runST (Prelude.mapM unsafeFreeze =<< p)
-{-# inline createT #-}
-
--- | Construct an array by repeatedly applying a generator
---   function to a seed. The generator function yields 'Just' the
---   next element and the new seed or 'Nothing' if there are no more
---   elements.
---
--- >>> unfoldr (\n -> if n == 0 then Nothing else Just (n,n-1) 10
---     <10,9,8,7,6,5,4,3,2,1>
-
--- Unfortunately, because we don't know ahead of time when to stop,
--- we need to construct a list and then turn it into an array.
-unfoldr :: (Contiguous arr, Element arr a)
-  => (b -> Maybe (a,b))
-  -> b
-  -> arr a
-unfoldr f z0 = create (unfoldrMutable f z0)
-{-# inline unfoldr #-}
-
--- | Construct a mutable array by repeatedly applying a generator
---   function to a seed. The generator function yields 'Just' the
---   next element and the new seed or 'Nothing' if there are no more
---   elements.
---
--- >>> unfoldrMutable (\n -> if n == 0 then Nothing else Just (n,n-1) 10
---     <10,9,8,7,6,5,4,3,2,1>
-
--- Unfortunately, because we don't know ahead of time when to stop,
--- we need to construct a list and then turn it into an array.
-unfoldrMutable :: (Contiguous arr, Element arr a, PrimMonad m)
-  => (b -> Maybe (a,b))
-  -> b
-  -> m (Mutable arr (PrimState m) a)
-unfoldrMutable f z0 = do
-  let go !sz s !xs = case f s of
-        Nothing -> pure (sz,xs)
-        Just (x,s') -> go (sz + 1) s' (x : xs)
-  (sz,xs) <- go 0 z0 []
-  unsafeFromListReverseMutableN sz xs
-{-# inline unfoldrMutable #-}
-
--- | Construct an array with at most n elements by repeatedly
---   applying the generator function to a seed. The generator function
---   yields 'Just' the next element and the new seed or 'Nothing' if
---   there are no more elements.
-unfoldrN :: (Contiguous arr, Element arr a)
-  => Int
-  -> (b -> Maybe (a, b))
-  -> b
-  -> arr a
-unfoldrN maxSz f z0 = create (unfoldrMutableN maxSz f z0)
-{-# inline unfoldrN #-}
-
--- | Construct a mutable array with at most n elements by repeatedly
---   applying the generator function to a seed. The generator function
---   yields 'Just' the next element and the new seed or 'Nothing' if
---   there are no more elements.
-unfoldrMutableN :: (Contiguous arr, Element arr a, PrimMonad m)
-  => Int
-  -> (b -> Maybe (a, b))
-  -> b
-  -> m (Mutable arr (PrimState m) a)
-unfoldrMutableN !maxSz f z0 = do
-  m <- new maxSz
-  let go !ix s = if ix < maxSz
-        then case f s of
-          Nothing -> pure ix
-          Just (x,s') -> do
-            write m ix x
-            go (ix + 1) s'
-        else pure ix
-  sz <- go 0 z0
-  shrink m sz
-{-# inline unfoldrMutableN #-}
-
--- | Convert an array to a list.
-toList :: (Contiguous arr, Element arr a)
-  => arr a
-  -> [a]
-toList arr = build (\c n -> foldr c n arr)
-{-# inline toList #-}
-
--- | Convert a mutable array to a list.
-
--- I don't think this can be expressed in terms of foldr/build,
--- so we just loop through the array.
-toListMutable :: (Contiguous arr, Element arr a, PrimMonad m)
-  => Mutable arr (PrimState m) a
-  -> m [a]
-toListMutable marr = do
-  sz <- sizeMut marr
-  let go !ix !acc = if ix >= 0
-        then do
-          x <- read marr ix
-          go (ix - 1) (x : acc)
-        else pure acc
-  go (sz - 1) []
-{-# inline toListMutable #-}
-
--- | Given an 'Int' that is representative of the length of
---   the list, convert the list into a mutable array of the
---   given length.
---
---   /Note/: calls 'error' if the given length is incorrect.
-fromListMutableN :: (Contiguous arr, Element arr a, PrimMonad m)
-  => Int
-  -> [a]
-  -> m (Mutable arr (PrimState m) a)
-fromListMutableN len vs = do
-  marr <- new len
-  let go [] !ix = if ix == len
-        then pure ()
-        else error "Data.Primitive.Contiguous.fromListN: list length less than specified size."
-      go (a:as) !ix = if ix < len
-        then do
-          write marr ix a
-          go as (ix + 1)
-        else error "Data.Primitive.Contiguous.fromListN: list length greater than specified size."
-  go vs 0
-  pure marr
-{-# inline fromListMutableN #-}
-
--- | Convert a list into a mutable array of the given length.
-fromListMutable :: (Contiguous arr, Element arr a, PrimMonad m)
-  => [a]
-  -> m (Mutable arr (PrimState m) a)
-fromListMutable xs = fromListMutableN (length xs) xs
-{-# inline fromListMutable #-}
-
--- | Given an 'Int' that is representative of the length of
---   the list, convert the list into a mutable array of the
---   given length.
---
---   /Note/: calls 'error' if the given length is incorrect.
-fromListN :: (Contiguous arr, Element arr a)
-  => Int
-  -> [a]
-  -> arr a
-fromListN len vs = create (fromListMutableN len vs)
-{-# inline fromListN #-}
-
--- | Convert a list into an array.
-fromList :: (Contiguous arr, Element arr a)
-  => [a]
-  -> arr a
-fromList vs = create (fromListMutable vs)
-{-# inline fromList #-}
-
--- | Modify the elements of a mutable array in-place.
-modify :: (Contiguous arr, Element arr a, PrimMonad m)
-  => (a -> a)
-  -> Mutable arr (PrimState m) a
-  -> m ()
-modify f marr = do
-  !sz <- sizeMut marr
-  let go !ix = when (ix < sz) $ do
-        x <- read marr ix
-        write marr ix (f x)
-        go (ix + 1)
-  go 0
-{-# inline modify #-}
-
--- | Strictly modify the elements of a mutable array in-place.
-modify' :: (Contiguous arr, Element arr a, PrimMonad m)
-  => (a -> a)
-  -> Mutable arr (PrimState m) a
-  -> m ()
-modify' f marr = do
-  !sz <- sizeMut marr
-  let go !ix = when (ix < sz) $ do
-        x <- read marr ix
-        let !y = f x
-        write marr ix y
-        go (ix + 1)
-  go 0
-{-# inline modify' #-}
-
--- | Yield an array of the given length containing the values
---   @x, 'succ' x, 'succ' ('succ' x)@ etc.
-enumFromN :: (Contiguous arr, Element arr a, Enum a)
-  => a
-  -> Int
-  -> arr a
-enumFromN z0 sz = create (enumFromMutableN z0 sz)
-{-# inline enumFromN #-}
-
--- | Yield a mutable array of the given length containing the values
---   @x, 'succ' x, 'succ' ('succ' x)@ etc.
-enumFromMutableN :: (Contiguous arr, Element arr a, PrimMonad m, Enum a)
-  => a
-  -> Int
-  -> m (Mutable arr (PrimState m) a)
-enumFromMutableN z0 !sz = do
-  m <- new sz
-  let go !ix z = if ix < sz
-        then do
-          write m ix z
-          go (ix + 1) (succ z)
-        else pure m
-  go 0 z0
-{-# inline enumFromMutableN #-}
-
--- | Lift an accumulating hash function over the elements of the array,
---   returning the final accumulated hash.
-liftHashWithSalt :: (Contiguous arr, Element arr a)
-  => (Int -> a -> Int)
-  -> Int
-  -> arr a
-  -> Int
-liftHashWithSalt f s0 arr = go 0 s0 where
-  sz = size arr
-  go !ix !s = if ix < sz
-    then
-      let !(# x #) = index# arr ix
-       in go (ix + 1) (f s x)
-    else hashIntWithSalt s ix
-{-# inline liftHashWithSalt #-}
-
--- | Reverse the elements of an array.
-reverse :: (Contiguous arr, Element arr a)
-  => arr a
-  -> arr a
-reverse arr = run $ do
-  marr <- new (size arr)
-  copy marr 0 (toSlice arr)
-  reverseMutable marr
-  unsafeFreeze marr
-{-# inline reverse #-}
-
--- | Reverse the elements of a mutable array, in-place.
-reverseMutable :: (Contiguous arr, Element arr a, PrimMonad m)
-  => Mutable arr (PrimState m) a
-  -> m ()
-reverseMutable marr = do
-  !sz <- sizeMut marr
-  reverseSlice marr 0 (sz - 1)
-{-# inline reverseMutable #-}
-
--- | Reverse the elements of a slice of a mutable array, in-place.
-reverseSlice :: (Contiguous arr, Element arr a, PrimMonad m)
-  => Mutable arr (PrimState m) a
-  -> Int -- ^ start index
-  -> Int -- ^ end index
-  -> m ()
-reverseSlice !marr !start !end = do
-  let go !s !e = if s >= e
-        then pure ()
-        else do
-          tmp <- read marr s
-          write marr s =<< read marr e
-          write marr e tmp
-          go (s+1) (e-1)
-  go start end
-{-# inline reverseSlice #-}
-
--- | This function does not behave deterministically. Optimization level and
--- inlining can affect its results. However, the one thing that can be counted
--- on is that if it returns 'True', the two immutable arrays are definitely the
--- same. This is useful as shortcut for equality tests. However, keep in mind
--- that a result of 'False' tells us nothing about the arguments.
-same :: ContiguousU arr => arr a -> arr a -> Bool
-same a b = isTrue# (sameMutableArrayArray#
-  (unsafeCoerce# (unlift a) :: MutableArrayArray# s)
-  (unsafeCoerce# (unlift b) :: MutableArrayArray# s))
-
-hashIntWithSalt :: Int -> Int -> Int
-hashIntWithSalt salt x = salt `combine` x
-{-# inline hashIntWithSalt #-}
-
-combine :: Int -> Int -> Int
-combine h1 h2 = (h1 * 16777619) `xor` h2
-{-# inline combine #-}
-
--- | Does the element occur in the structure?
-elem :: (Contiguous arr, Element arr a, Eq a) => a -> arr a -> Bool
-elem a !arr =
-  let !sz = size arr
-      go !ix
-        | ix < sz = case index# arr ix of
-            !(# x #) -> if a == x
-              then True
-              else go (ix + 1)
-        | otherwise = False
-  in go 0
-{-# inline elem #-}
-
--- | The largest element of a structure.
-maximum :: (Contiguous arr, Element arr a, Ord a) => arr a -> Maybe a
-maximum = maximumBy compare
-{-# inline maximum #-}
-
--- | The least element of a structure.
-minimum :: (Contiguous arr, Element arr a, Ord a) => arr a -> Maybe a
-minimum = minimumBy compare
-{-# inline minimum #-}
-
--- | The largest element of a structure with respect to the
---   given comparison function.
-maximumBy :: (Contiguous arr, Element arr a)
-  => (a -> a -> Ordering)
-  -> arr a
-  -> Maybe a
-maximumBy f arr =
-  let !sz = size arr
-      go !ix o = if ix < sz
-        then case index# arr ix of
-          !(# x #) -> go (ix + 1) (case f x o of { GT -> x; _ -> o; })
-        else o
-  in if sz == 0
-    then Nothing
-    else Just (go 0 (index arr 0))
-{-# inline maximumBy #-}
-
--- | The least element of a structure with respect to the
---   given comparison function.
-minimumBy :: (Contiguous arr, Element arr a)
-  => (a -> a -> Ordering)
-  -> arr a
-  -> Maybe a
-minimumBy f arr =
-  let !sz = size arr
-      go !ix o = if ix < sz
-        then case index# arr ix of
-          !(# x #) -> go (ix + 1) (case f x o of { GT -> o; _ -> x; })
-        else o
-  in if sz == 0
-    then Nothing
-    else Just (go 0 (index arr 0))
-{-# inline minimumBy #-}
-
--- | 'find' takes a predicate and an array, and returns the leftmost
---   element of the array matching the prediate, or 'Nothing' if there
---   is no such element.
-find :: (Contiguous arr, Element arr a)
-  => (a -> Bool)
-  -> arr a
-  -> Maybe a
-find p = coerce . (foldMap (\x -> if p x then Just (First x) else Nothing))
-{-# inline find #-}
-
--- | 'findIndex' takes a predicate and an array, and returns the index of
---   the leftmost element of the array matching the prediate, or 'Nothing'
---   if there is no such element.
-findIndex :: (Contiguous arr, Element arr a)
-  => (a -> Bool)
-  -> arr a
-  -> Maybe Int
-findIndex p xs = loop 0
-  where
-  loop i
-    | i < size xs = if p (index xs i) then Just i else loop (i + 1)
-    | otherwise = Nothing
-{-# inline findIndex #-}
-
--- | Swap the elements of the mutable array at the given indices.
-swap :: (Contiguous arr, Element arr a, PrimMonad m)
-  => Mutable arr (PrimState m) a
-  -> Int
-  -> Int
-  -> m ()
-swap !marr !ix1 !ix2 = do
-  atIx1 <- read marr ix1
-  atIx2 <- read marr ix2
-  write marr ix1 atIx2
-  write marr ix2 atIx1
-{-# inline swap #-}
-
--- | Extracts from an array of 'Either' all the 'Left' elements.
--- All the 'Left' elements are extracted in order.
-lefts :: forall arr a b.
-  ( Contiguous arr
-  , Element arr a
-  , Element arr (Either a b)
-  ) => arr (Either a b)
-    -> arr a
-lefts !arr = create $ do
-  let !sz = size arr
-      go :: Int -> [a] -> Int -> ST s (Int, [a])
-      go !ix !as !acc = if ix < sz
-        then do
-          indexM arr ix >>= \case
-            Left a -> go (ix + 1) (a:as) (acc + 1)
-            Right _ -> go (ix + 1) as acc
-        else pure (acc, as)
-  (len, as) <- go 0 [] 0
-  unsafeFromListReverseMutableN len as
-{-# inline lefts #-}
-
--- | Extracts from an array of 'Either' all the 'Right' elements.
--- All the 'Right' elements are extracted in order.
-rights :: forall arr a b.
-  ( Contiguous arr
-  , Element arr b
-  , Element arr (Either a b)
-  ) => arr (Either a b)
-    -> arr b
-rights !arr = create $ do
-  let !sz = size arr
-      go :: Int -> [b] -> Int -> ST s (Int, [b])
-      go !ix !bs !acc = if ix < sz
-        then do
-          indexM arr ix >>= \case
-            Left _ -> go (ix + 1) bs acc
-            Right b -> go (ix + 1) (b:bs) (acc + 1)
-        else pure (acc, bs)
-  (len, bs) <- go 0 [] 0
-  unsafeFromListReverseMutableN len bs
-{-# inline rights #-}
-
--- | Partitions an array of 'Either' into two arrays.
--- All the 'Left' elements are extracted, in order, to the first
--- component of the output. Similarly the 'Right' elements are extracted
--- to the second component of the output.
-partitionEithers :: forall arr a b.
-  ( Contiguous arr
-  , Element arr a
-  , Element arr b
-  , Element arr (Either a b)
-  ) => arr (Either a b)
-    -> (arr a, arr b)
-partitionEithers !arr = runST $ do
-  let !sz = size arr
-      go :: Int -> [a] -> [b] -> Int -> Int -> ST s (Int, Int, [a], [b])
-      go !ix !as !bs !accA !accB = if ix < sz
-        then do
-          indexM arr ix >>= \case
-            Left a -> go (ix + 1) (a:as) bs (accA + 1) accB
-            Right b -> go (ix + 1) as (b:bs) accA (accB + 1)
-          else pure (accA, accB, as, bs)
-  (lenA, lenB, as, bs) <- go 0 [] [] 0 0
-  arrA <- unsafeFreeze =<< unsafeFromListReverseMutableN lenA as
-  arrB <- unsafeFreeze =<< unsafeFromListReverseMutableN lenB bs
-  pure (arrA, arrB)
-{-# inline partitionEithers #-}
-
--- | 'scanl' is similar to 'foldl', but returns an array of
---   successive reduced values from the left:
---
---   > scanl f z [x1, x2, ...] = [z, f z x1, f (f z x1) x2, ...]
---
---   Note that
---
---   > last (toList (scanl f z xs)) == foldl f z xs.
-scanl ::
-  ( Contiguous arr1
-  , Contiguous arr2
-  , Element arr1 a
-  , Element arr2 b
-  ) => (b -> a -> b)
-    -> b
-    -> arr1 a
-    -> arr2 b
-scanl f = iscanl (const f)
-{-# inline scanl #-}
-
--- | A variant of 'scanl' whose function argument takes the current
---   index as an argument.
-iscanl ::
-  ( Contiguous arr1
-  , Contiguous arr2
-  , Element arr1 a
-  , Element arr2 b
-  ) => (Int -> b -> a -> b)
-    -> b
-    -> arr1 a
-    -> arr2 b
-iscanl f q as = internalScanl (size as + 1) f q as
-{-# inline iscanl #-}
-
--- | A strictly accumulating version of 'scanl'.
-scanl' ::
-  ( Contiguous arr1
-  , Contiguous arr2
-  , Element arr1 a
-  , Element arr2 b
-  ) => (b -> a -> b)
-    -> b
-    -> arr1 a
-    -> arr2 b
-scanl' f = iscanl' (const f)
-{-# inline scanl' #-}
-
--- | A strictly accumulating version of 'iscanl'.
-iscanl' ::
-  ( Contiguous arr1
-  , Contiguous arr2
-  , Element arr1 a
-  , Element arr2 b
-  ) => (Int -> b -> a -> b)
-    -> b
-    -> arr1 a
-    -> arr2 b
-iscanl' f !q as = internalScanl' (size as + 1) f q as
-{-# inline iscanl' #-}
-
--- Internal only. The first argument is the size of the array
--- argument. This function helps prevent duplication.
-internalScanl ::
-  ( Contiguous arr1
-  , Contiguous arr2
-  , Element arr1 a
-  , Element arr2 b
-  ) => Int
-    -> (Int -> b -> a -> b)
-    -> b
-    -> arr1 a
-    -> arr2 b
-internalScanl !sz f !q as = create $ do
-  !marr <- new sz
-  let go !ix acc = when (ix < sz) $ do
-        write marr ix acc
-        x <- indexM as ix
-        go (ix + 1) (f ix acc x)
-  go 0 q
-  pure marr
-{-# inline internalScanl #-}
-
--- Internal only. The first argument is the size of the array
--- argument. This function helps prevent duplication.
-internalScanl' ::
-  ( Contiguous arr1
-  , Contiguous arr2
-  , Element arr1 a
-  , Element arr2 b
-  ) => Int
-    -> (Int -> b -> a -> b)
-    -> b
-    -> arr1 a
-    -> arr2 b
-internalScanl' !sz f !q as = create $ do
-  !marr <- new sz
-  let go !ix !acc = when (ix < sz) $ do
-        write marr ix acc
-        x <- indexM as ix
-        go (ix + 1) (f ix acc x)
-  go 0 q
-  pure marr
-{-# inline internalScanl' #-}
-
--- | A prescan.
---
---   @prescanl f z = init . scanl f z@
---
---   Example: @prescanl (+) 0 \<1,2,3,4\> = \<0,1,3,6\>@
-prescanl ::
-  ( Contiguous arr1
-  , Contiguous arr2
-  , Element arr1 a
-  , Element arr2 b
-  ) => (b -> a -> b)
-    -> b
-    -> arr1 a
-    -> arr2 b
-prescanl f = iprescanl (const f)
-{-# inline prescanl #-}
-
--- | A variant of 'prescanl' where the function argument takes
---   the current index of the array as an additional argument.
-iprescanl ::
-  ( Contiguous arr1
-  , Contiguous arr2
-  , Element arr1 a
-  , Element arr2 b
-  ) => (Int -> b -> a -> b)
-    -> b
-    -> arr1 a
-    -> arr2 b
-iprescanl f q as = internalScanl (size as) f q as
-{-# inline iprescanl #-}
-
--- | Like 'prescanl', but with a strict accumulator.
-prescanl' ::
-  ( Contiguous arr1
-  , Contiguous arr2
-  , Element arr1 a
-  , Element arr2 b
-  ) => (b -> a -> b)
-    -> b
-    -> arr1 a
-    -> arr2 b
-prescanl' f = iprescanl (const f)
-{-# inline prescanl' #-}
-
--- | Like 'iprescanl', but with a strict accumulator.
-iprescanl' ::
-  ( Contiguous arr1
-  , Contiguous arr2
-  , Element arr1 a
-  , Element arr2 b
-  ) => (Int -> b -> a -> b)
-    -> b
-    -> arr1 a
-    -> arr2 b
-iprescanl' f !q as = internalScanl' (size as) f q as
-{-# inline iprescanl' #-}
-
--- | 'zipWith' generalises 'zip' by zipping with the function
---   given as the first argument, instead of a tupling function.
---   For example, 'zipWith' (+) is applied to two arrays to produce
---   an array of the corresponding sums.
-zipWith ::
-  ( Contiguous arr1
-  , Contiguous arr2
-  , Contiguous arr3
-  , Element arr1 a
-  , Element arr2 b
-  , Element arr3 c
-  ) => (a -> b -> c)
-    -> arr1 a
-    -> arr2 b
-    -> arr3 c
-zipWith f = izipWith (\_ a b -> f a b)
-{-# inline zipWith #-}
-
--- | Variant of 'zipWith' that provides the index of each pair of elements.
-izipWith ::
-  ( Contiguous arr1
-  , Contiguous arr2
-  , Contiguous arr3
-  , Element arr1 a
-  , Element arr2 b
-  , Element arr3 c
-  ) => (Int -> a -> b -> c)
-    -> arr1 a
-    -> arr2 b
-    -> arr3 c
-izipWith f as bs = create $ do
-  let !sz = min (size as) (size bs)
-  !marr <- new sz
-  let go !ix = when (ix < sz) $ do
-        a <- indexM as ix
-        b <- indexM bs ix
-        let !g = f ix a b
-        write marr ix g
-        go (ix + 1)
-  go 0
-  pure marr
-{-# inline izipWith #-}
-
--- | Variant of 'zipWith' that accepts an accumulator, performing a lazy
--- right fold over both arrays.
-foldrZipWith ::
-  ( Contiguous arr1
-  , Contiguous arr2
-  , Element arr1 a
-  , Element arr2 b
-  ) => (a -> b -> c -> c)
-    -> c
-    -> arr1 a
-    -> arr2 b
-    -> c
-foldrZipWith f = ifoldrZipWith (\_ x y c -> f x y c)
-{-# inline foldrZipWith #-}
-
--- | Variant of 'zipWith' that accepts an accumulator, performing a strict
--- left monadic fold over both arrays.
-foldlZipWithM' ::
-  ( Contiguous arr1
-  , Contiguous arr2
-  , Element arr1 a
-  , Element arr2 b
-  , Monad m
-  ) => (c -> a -> b -> m c)
-    -> c
-    -> arr1 a
-    -> arr2 b
-    -> m c
-foldlZipWithM' f = ifoldlZipWithM' (\_ x y c -> f x y c)
-{-# inline foldlZipWithM' #-}
-
--- | Variant of 'foldrZipWith' that provides the index of each pair of elements.
-ifoldrZipWith ::
-  ( Contiguous arr1
-  , Contiguous arr2
-  , Element arr1 a
-  , Element arr2 b
-  ) => (Int -> a -> b -> c -> c)
-    -> c
-    -> arr1 a
-    -> arr2 b
-    -> c
-ifoldrZipWith f z = \arr1 arr2 ->
-  let !sz = min (size arr1) (size arr2)
-      go !ix = if sz > ix
-        then case index# arr1 ix of
-          (# x #) -> case index# arr2 ix of
-            (# y #) -> f ix x y (go (ix + 1))
-        else z
-  in go 0
-{-# inline ifoldrZipWith #-}
-
-foldlZipWith' ::
-  ( Contiguous arr1
-  , Contiguous arr2
-  , Element arr1 a
-  , Element arr2 b
-  ) => (c -> a -> b -> c)
-    -> c
-    -> arr1 a
-    -> arr2 b
-    -> c
-foldlZipWith' f = ifoldlZipWith' (\_ x y c -> f x y c)
-{-# inline foldlZipWith' #-}
-
-ifoldlZipWith' ::
-  ( Contiguous arr1
-  , Contiguous arr2
-  , Element arr1 a
-  , Element arr2 b
-  ) => (Int -> c -> a -> b -> c)
-    -> c
-    -> arr1 a
-    -> arr2 b
-    -> c
-ifoldlZipWith' f !z !arr1 !arr2 =
-  let !sz = min (size arr1) (size arr2)
-      go !ix !acc = if ix == sz
-        then acc
-        else case index# arr1 ix of
-          (# x #) -> case index# arr2 ix of
-            (# y #) -> go (ix + 1) (f ix acc x y)
-  in go 0 z
-{-# inline ifoldlZipWith' #-}
-
--- | Variant of 'foldlZipWithM\'' that provides the index of each pair of elements.
-ifoldlZipWithM' ::
-  ( Contiguous arr1
-  , Contiguous arr2
-  , Element arr1 a
-  , Element arr2 b
-  , Monad m
-  ) => (Int -> c -> a -> b -> m c)
-    -> c
-    -> arr1 a
-    -> arr2 b
-    -> m c
-ifoldlZipWithM' f z = \arr1 arr2 ->
-  let !sz = min (size arr1) (size arr2)
-      go !ix !acc = if sz > ix
-        then case index# arr1 ix of
-          (# x #) -> case index# arr2 ix of
-            (# y #) -> do
-              acc' <- f ix acc x y
-              go (ix + 1) acc'
-        else pure acc
-  in go 0 z
-{-# inline ifoldlZipWithM' #-}
-
--- | 'zip' takes two arrays and returns an array of
---   corresponding pairs.
---
---   > zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]
---
---   If one input array is shorter than the other, excess
---   elements of the longer array are discarded:
---
---   > zip [1] ['a', 'b'] = [(1, 'a')]
---   > zip [1, 2] ['a'] = [(1, 'a')]
---
-zip ::
-  ( Contiguous arr1
-  , Contiguous arr2
-  , Contiguous arr3
-  , Element arr1 a
-  , Element arr2 b
-  , Element arr3 (a, b)
-  ) => arr1 a
-    -> arr2 b
-    -> arr3 (a, b)
-zip = zipWith (,)
-{-# inline zip #-}
-
--- | Replace all locations in the input with the same value.
---
---   Equivalent to Data.Functor.'Data.Functor.<$'.
-(<$) ::
-  ( Contiguous arr1
-  , Contiguous arr2
-  , Element arr1 b
-  , Element arr2 a
-  ) => a -> arr1 b -> arr2 a
-a <$ barr = create (replicateMut (size barr) a)
-{-# inline (<$) #-}
-
--- | Sequential application.
---
---   Equivalent to Control.Applicative.'Control.Applicative.<*>'.
-ap ::
-  ( Contiguous arr1
-  , Contiguous arr2
-  , Contiguous arr3
-  , Element arr1 (a -> b)
-  , Element arr2 a
-  , Element arr3 b
-  ) => arr1 (a -> b) -> arr2 a -> arr3 b
-ap fs xs = create $ do
-  marr <- new (szfs * szxs)
-  let go1 !ix = when (ix < szfs) $ do
-        f <- indexM fs ix
-        go2 (ix * szxs) f 0
-        go1 (ix + 1)
-      go2 !off f !j = when (j < szxs) $ do
-        x <- indexM xs j
-        write marr (off + j) (f x)
-        go2 off f (j + 1)
-  go1 0
-  pure marr
-  where
-    !szfs = size fs
-    !szxs = size xs
-{-# inline ap #-}
-
-all :: (Contiguous arr, Element arr a) => (a -> Bool) -> arr a -> Bool
-all f = foldr (\x acc -> f x && acc) True
-{-# inline all #-}
-
-any :: (Contiguous arr, Element arr a) => (a -> Bool) -> arr a -> Bool
-any f = foldr (\x acc -> f x || acc) False
-{-# inline any #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeFamilyDependencies #-}
+{-# LANGUAGE UnboxedTuples #-}
+
+{- | The contiguous package presents a common API to a number of contiguous
+array types and their mutable counterparts. This is enabled with the
+'Contiguous' typeclass, which parameterises over a contiguous array type and
+defines the core operations. However, the stable part of the interface is
+contained in this module, which combines those primitives into common,
+efficient array algorithms suitable for replacing pointer-heavy list
+manipulations.
+-}
+module Data.Primitive.Contiguous
+  ( -- * Accessors
+
+    -- ** Length Information
+    size
+  , sizeMut
+  , null
+
+    -- ** Indexing
+  , index
+  , index#
+  , read
+
+    -- ** Monadic indexing
+  , indexM
+
+    -- * Construction
+
+    -- ** Initialisation
+  , empty
+  , new
+  , singleton
+  , doubleton
+  , tripleton
+  , quadrupleton
+  , quintupleton
+  , sextupleton
+  , replicate
+  , replicateMut
+  , generate
+  , generateM
+  , generateMutable
+  , iterateN
+  , iterateMutableN
+  , write
+
+    -- ** Fixed Length
+  , construct1
+  , construct2
+  , construct3
+  , construct4
+  , construct5
+  , construct6
+
+    -- ** Running
+  , run
+
+    -- ** Monadic initialisation
+  , replicateMutM
+  , generateMutableM
+  , iterateMutableNM
+  , create
+  , createT
+
+    -- ** Unfolding
+  , unfoldr
+  , unfoldrN
+  , unfoldrMutable
+
+    -- ** Enumeration
+  , enumFromN
+  , enumFromMutableN
+
+    -- ** Concatenation
+  , append
+
+    -- ** Splitting and Splicing
+  , insertAt
+
+    -- * Slicing
+  , Slice
+  , MutableSlice
+  , slice
+  , sliceMut
+  , toSlice
+  , toSliceMut
+
+    -- * Modifying arrays
+  , replaceAt
+  , modifyAt
+  , modifyAt'
+  , modifyAtF
+  , modifyAtF'
+  , deleteAt
+
+    -- ** Permutations
+  , reverse
+  , reverseMutable
+  , reverseSlice
+
+    -- ** Resizing
+  , resize
+  , shrink
+  , unsafeShrinkAndFreeze
+
+    -- * Elementwise operations
+
+    -- ** Mapping
+  , map
+  , map'
+  , mapMutable
+  , mapMutable'
+  , imap
+  , imap'
+  , imapMutable
+  , imapMutable'
+  , modify
+  , modify'
+  , mapMaybe
+
+    -- ** Zipping
+  , zip
+  , zipWith
+  , izipWith
+
+    -- ** Specific elements
+  , swap
+
+    -- * Working with predicates
+
+    -- ** Filtering
+  , filter
+  , ifilter
+  , catMaybes
+  , lefts
+  , rights
+  , partitionEithers
+
+    -- ** Searching
+  , find
+  , findIndex
+  , elem
+  , maximum
+  , minimum
+  , maximumBy
+  , minimumBy
+
+    -- ** Comparing for equality
+  , equals
+  , equalsMut
+  , same
+
+    -- * Folds
+  , foldl
+  , foldl'
+  , foldr
+  , foldr'
+  , foldMap
+  , foldMap'
+  , foldlMap'
+  , ifoldl'
+  , ifoldr
+  , ifoldr'
+  , ifoldlMap'
+  , ifoldlMap1'
+  , foldlM'
+  , ifoldlM'
+  , foldrM'
+  , asum
+  , all
+  , any
+
+    -- ** Zipping Folds
+  , foldrZipWith
+  , ifoldrZipWith
+  , foldlZipWith'
+  , ifoldlZipWith'
+  , foldlZipWithM'
+  , ifoldlZipWithM'
+
+    -- * Traversals
+  , traverse
+  , traverse_
+  , itraverse
+  , itraverse_
+  , traverseP
+  , itraverseP
+  , mapM
+  , forM
+  , mapM_
+  , forM_
+  , for
+  , for_
+  , sequence
+  , sequence_
+
+    -- * Typeclass method defaults
+  , (<$)
+  , ap
+
+    -- * Prefix sums (scans)
+  , scanl
+  , scanl'
+  , iscanl
+  , iscanl'
+  , prescanl
+  , prescanl'
+  , iprescanl
+  , iprescanl'
+  -- , postscanl
+  -- , ipostscanl
+
+  , mapAccum'
+  , mapAccumLM'
+
+    -- * Conversions
+
+    -- ** Lists
+  , fromList
+  , fromListN
+  , fromListMutable
+  , fromListMutableN
+  , unsafeFromListN
+  , unsafeFromListReverseN
+  , unsafeFromListReverseMutableN
+  , toList
+  , toListMutable
+
+    -- ** Other array types
+  , convert
+  , lift
+  , liftMut
+  , unlift
+  , unliftMut
+
+    -- ** Between mutable and immutable variants
+  , clone
+  , cloneMut
+  , copy
+  , copyMut
+  , freeze
+  , thaw
+  , unsafeFreeze
+
+    -- * Hashing
+  , liftHashWithSalt
+
+    -- * Forcing an array and its contents
+  , rnf
+
+    -- * Classes
+  , Contiguous (Mutable, Element, Sliced, MutableSliced)
+  , ContiguousU
+  , Always
+
+    -- * Re-Exports
+  , Array
+  , MutableArray
+  , SmallArray
+  , SmallMutableArray
+  , PrimArray
+  , MutablePrimArray
+  , UnliftedArray
+  , MutableUnliftedArray
+  ) where
+
+import Control.Monad.Primitive
+import Data.Primitive hiding (fromList, fromListN)
+import Data.Primitive.Unlifted.Array
+import Prelude hiding (Foldable (..), all, any, filter, map, mapM, mapM_, read, replicate, reverse, scanl, sequence, sequence_, traverse, zip, zipWith, (<$))
+
+import Control.Monad (when)
+import Control.Monad.ST (ST, runST)
+import Data.Bits (xor)
+import Data.Coerce (coerce)
+import Data.Foldable (length)
+import Data.Primitive.Contiguous.Class (Always, Contiguous (..), ContiguousU (..), MutableSlice, Slice)
+import Data.Semigroup (First (..))
+import Data.Word (Word8)
+import GHC.Base (build)
+import GHC.Exts (Int (..), MutableArrayArray#, dataToTag#, isTrue#, sameMutableArrayArray#, unsafeCoerce#)
+
+import qualified Control.Applicative as A
+import qualified Prelude
+
+construct1 ::
+  (Contiguous arr, Element arr a) =>
+  a ->
+  arr a
+{-# INLINE construct1 #-}
+construct1 = singleton
+
+construct2 ::
+  (Contiguous arr, Element arr a) =>
+  a ->
+  a ->
+  arr a
+{-# INLINE construct2 #-}
+construct2 = doubleton
+
+construct3 ::
+  (Contiguous arr, Element arr a) =>
+  a ->
+  a ->
+  a ->
+  arr a
+{-# INLINE construct3 #-}
+construct3 = tripleton
+
+construct4 ::
+  (Contiguous arr, Element arr a) =>
+  a ->
+  a ->
+  a ->
+  a ->
+  arr a
+{-# INLINE construct4 #-}
+construct4 = quadrupleton
+
+construct5 ::
+  (Contiguous arr, Element arr a) =>
+  a ->
+  a ->
+  a ->
+  a ->
+  a ->
+  arr a
+{-# INLINE construct5 #-}
+construct5 = quintupleton
+
+construct6 ::
+  (Contiguous arr, Element arr a) =>
+  a ->
+  a ->
+  a ->
+  a ->
+  a ->
+  a ->
+  arr a
+{-# INLINE construct6 #-}
+construct6 = sextupleton
+
+-- | Append two arrays.
+append :: (Contiguous arr, Element arr a) => arr a -> arr a -> arr a
+append !a !b = run $ do
+  m <- new (size a + size b)
+  copy m 0 (toSlice a)
+  copy m (size a) (toSlice b)
+  unsafeFreeze m
+{-# INLINE append #-}
+
+-- | Delete the element at the given position.
+deleteAt :: (Contiguous arr, Element arr a) => arr a -> Int -> arr a
+deleteAt src i = run $ do
+  dst <- thaw (slice src 0 (size src - 1))
+  let !i' = i + 1
+  copy dst i (slice src i' (size src - i'))
+  unsafeFreeze dst
+{-# INLINE deleteAt #-}
+
+{- | Create a copy of an array except the element at the index is replaced with
+  the given value.
+-}
+replaceAt :: (Contiguous arr, Element arr a) => arr a -> Int -> a -> arr a
+replaceAt src i x = create $ do
+  dst <- thaw (toSlice src)
+  write dst i x
+  pure dst
+{-# INLINE replaceAt #-}
+
+modifyAt ::
+  (Contiguous arr, Element arr a) =>
+  (a -> a) ->
+  arr a ->
+  Int ->
+  arr a
+modifyAt f src i = replaceAt src i $ f (index src i)
+{-# INLINE modifyAt #-}
+
+{- | Variant of modifyAt that forces the result before installing it in the
+array.
+-}
+modifyAt' ::
+  (Contiguous arr, Element arr a) =>
+  (a -> a) ->
+  arr a ->
+  Int ->
+  arr a
+modifyAt' f src i = replaceAt src i $! f (index src i)
+{-# INLINE modifyAt' #-}
+
+modifyAtF ::
+  (Contiguous arr, Element arr a, Functor f) =>
+  (a -> f a) ->
+  arr a ->
+  Int ->
+  f (arr a)
+modifyAtF f src i = replaceAt src i <$> f (index src i)
+{-# INLINE modifyAtF #-}
+
+{- | Variant of modifyAtF that forces the result before installing it in the
+array. Note that this requires 'Monad' rather than 'Functor'.
+-}
+modifyAtF' ::
+  (Contiguous arr, Element arr a, Monad f) =>
+  (a -> f a) ->
+  arr a ->
+  Int ->
+  f (arr a)
+modifyAtF' f src i = do
+  !r <- f (index src i)
+  let !dst = replaceAt src i r
+  pure dst
+{-# INLINE modifyAtF' #-}
+
+-- | Map over the elements of an array with the index.
+imap ::
+  (Contiguous arr1, Element arr1 b, Contiguous arr2, Element arr2 c) =>
+  (Int -> b -> c) ->
+  arr1 b ->
+  arr2 c
+imap f a = run $ do
+  mb <- new (size a)
+  let go !i
+        | i == size a = pure ()
+        | otherwise = do
+            x <- indexM a i
+            write mb i (f i x)
+            go (i + 1)
+  go 0
+  unsafeFreeze mb
+{-# INLINE imap #-}
+
+{- | Map strictly over the elements of an array with the index.
+
+  Note that because a new array must be created, the resulting
+  array type can be /different/ than the original.
+-}
+imap' ::
+  (Contiguous arr1, Element arr1 b, Contiguous arr2, Element arr2 c) =>
+  (Int -> b -> c) ->
+  arr1 b ->
+  arr2 c
+imap' f a = run $ do
+  mb <- new (size a)
+  let go !i
+        | i == size a = pure ()
+        | otherwise = do
+            x <- indexM a i
+            let !b = f i x
+            write mb i b
+            go (i + 1)
+  go 0
+  unsafeFreeze mb
+{-# INLINE imap' #-}
+
+{- | Map over the elements of an array.
+
+  Note that because a new array must be created, the resulting
+  array type can be /different/ than the original.
+-}
+map ::
+  (Contiguous arr1, Element arr1 b, Contiguous arr2, Element arr2 c) =>
+  (b -> c) ->
+  arr1 b ->
+  arr2 c
+map f a = run $ do
+  mb <- new (size a)
+  let go !i
+        | i == size a = pure ()
+        | otherwise = do
+            x <- indexM a i
+            write mb i (f x)
+            go (i + 1)
+  go 0
+  unsafeFreeze mb
+{-# INLINE map #-}
+
+{- | Map strictly over the elements of an array.
+
+  Note that because a new array must be created, the resulting
+  array type can be /different/ than the original.
+-}
+map' ::
+  (Contiguous arr1, Element arr1 b, Contiguous arr2, Element arr2 c) =>
+  (b -> c) ->
+  arr1 b ->
+  arr2 c
+map' f a = run $ do
+  mb <- new (size a)
+  let go !i
+        | i == size a = pure ()
+        | otherwise = do
+            x <- indexM a i
+            let !b = f x
+            write mb i b
+            go (i + 1)
+  go 0
+  unsafeFreeze mb
+{-# INLINE map' #-}
+
+-- | Convert one type of array into another.
+convert ::
+  (Contiguous arr1, Element arr1 b, Contiguous arr2, Element arr2 b) =>
+  arr1 b ->
+  arr2 b
+convert a = map id a
+{-# INLINE convert #-}
+
+-- | Right fold over the element of an array.
+foldr :: (Contiguous arr, Element arr a) => (a -> b -> b) -> b -> arr a -> b
+{-# INLINE foldr #-}
+foldr f z = \arr ->
+  let !sz = size arr
+      go !ix =
+        if sz > ix
+          then case index# arr ix of
+            (# x #) -> f x (go (ix + 1))
+          else z
+   in go 0
+
+{- | Right fold over the element of an array, lazy in the accumulator,
+provides index to the step function.
+-}
+ifoldr :: (Contiguous arr, Element arr a) => (Int -> a -> b -> b) -> b -> arr a -> b
+{-# INLINE ifoldr #-}
+ifoldr f z = \arr ->
+  let !sz = size arr
+      go !ix =
+        if sz > ix
+          then case index# arr ix of
+            (# x #) -> f ix x (go (ix + 1))
+          else z
+   in go 0
+
+-- | Strict right fold over the elements of an array.
+foldr' :: (Contiguous arr, Element arr a) => (a -> b -> b) -> b -> arr a -> b
+foldr' f !z = \arr ->
+  let go !ix !acc =
+        if ix == -1
+          then acc
+          else case index# arr ix of
+            (# x #) -> go (ix - 1) (f x acc)
+   in go (size arr - 1) z
+{-# INLINE foldr' #-}
+
+-- | Left fold over the elements of an array.
+foldl :: (Contiguous arr, Element arr a) => (b -> a -> b) -> b -> arr a -> b
+foldl f z = \arr ->
+  let !sz = size arr
+      go !ix acc =
+        if ix == sz
+          then acc
+          else case index# arr ix of
+            (# x #) -> go (ix + 1) (f acc x)
+   in go 0 z
+{-# INLINE foldl #-}
+
+-- | Strict left fold over the elements of an array.
+foldl' :: (Contiguous arr, Element arr a) => (b -> a -> b) -> b -> arr a -> b
+foldl' f !z = \arr ->
+  let !sz = size arr
+      go !ix !acc =
+        if ix == sz
+          then acc
+          else case index# arr ix of
+            (# x #) -> go (ix + 1) (f acc x)
+   in go 0 z
+{-# INLINE foldl' #-}
+
+{- | Strict left fold over the elements of an array, where the accumulating
+  function cares about the index of the element.
+-}
+ifoldl' ::
+  (Contiguous arr, Element arr a) =>
+  (b -> Int -> a -> b) ->
+  b ->
+  arr a ->
+  b
+ifoldl' f !z = \arr ->
+  let !sz = size arr
+      go !ix !acc =
+        if ix == sz
+          then acc
+          else case index# arr ix of
+            (# x #) -> go (ix + 1) (f acc ix x)
+   in go 0 z
+{-# INLINE ifoldl' #-}
+
+{- | Strict right fold over the elements of an array, where the accumulating
+  function cares about the index of the element.
+-}
+ifoldr' ::
+  (Contiguous arr, Element arr a) =>
+  (Int -> a -> b -> b) ->
+  b ->
+  arr a ->
+  b
+ifoldr' f !z = \arr ->
+  let !sz = size arr
+      go !ix !acc =
+        if ix == (-1)
+          then acc
+          else case index# arr ix of
+            (# x #) -> go (ix - 1) (f ix x acc)
+   in go (sz - 1) z
+{-# INLINE ifoldr' #-}
+
+-- | Monoidal fold over the element of an array.
+foldMap :: (Contiguous arr, Element arr a, Monoid m) => (a -> m) -> arr a -> m
+foldMap f = \arr ->
+  let !sz = size arr
+      go !ix =
+        if sz > ix
+          then case index# arr ix of
+            (# x #) -> mappend (f x) (go (ix + 1))
+          else mempty
+   in go 0
+{-# INLINE foldMap #-}
+
+-- | Strict monoidal fold over the elements of an array.
+foldMap' ::
+  (Contiguous arr, Element arr a, Monoid m) =>
+  (a -> m) ->
+  arr a ->
+  m
+foldMap' f = \arr ->
+  let !sz = size arr
+      go !ix !acc =
+        if ix == sz
+          then acc
+          else case index# arr ix of
+            (# x #) -> go (ix + 1) (mappend acc (f x))
+   in go 0 mempty
+{-# INLINE foldMap' #-}
+
+-- | Strict left monoidal fold over the elements of an array.
+foldlMap' ::
+  (Contiguous arr, Element arr a, Monoid m) =>
+  (a -> m) ->
+  arr a ->
+  m
+foldlMap' = foldMap'
+{-# INLINE foldlMap' #-}
+
+-- | Strict monoidal fold over the elements of an array.
+ifoldlMap' ::
+  (Contiguous arr, Element arr a, Monoid m) =>
+  (Int -> a -> m) ->
+  arr a ->
+  m
+ifoldlMap' f = \arr ->
+  let !sz = size arr
+      go !ix !acc =
+        if ix == sz
+          then acc
+          else case index# arr ix of
+            (# x #) -> go (ix + 1) (mappend acc (f ix x))
+   in go 0 mempty
+{-# INLINE ifoldlMap' #-}
+
+-- | Strict monoidal fold over the elements of an array.
+ifoldlMap1' ::
+  (Contiguous arr, Element arr a, Semigroup m) =>
+  (Int -> a -> m) ->
+  arr a ->
+  m
+ifoldlMap1' f = \arr ->
+  let !sz = size arr
+      go !ix !acc =
+        if ix == sz
+          then acc
+          else case index# arr ix of
+            (# x #) -> go (ix + 1) (acc <> f ix x)
+      !(# e0 #) = index# arr 0
+   in go 1 (f 0 e0)
+{-# INLINE ifoldlMap1' #-}
+
+-- | Strict right monadic fold over the elements of an array.
+foldrM' ::
+  (Contiguous arr, Element arr a, Monad m) =>
+  (a -> b -> m b) ->
+  b ->
+  arr a ->
+  m b
+foldrM' f !z0 = \arr ->
+  let !sz = size arr
+      go !ix !acc1 =
+        if ix >= 0
+          then do
+            let (# x #) = index# arr ix
+            acc2 <- f x acc1
+            go (ix - 1) acc2
+          else pure acc1
+   in go (sz - 1) z0
+{-# INLINE foldrM' #-}
+
+-- | Strict left monadic fold over the elements of an array.
+foldlM' ::
+  (Contiguous arr, Element arr a, Monad m) =>
+  (b -> a -> m b) ->
+  b ->
+  arr a ->
+  m b
+foldlM' f !z0 = \arr ->
+  let !sz = size arr
+      go !ix !acc1 =
+        if ix < sz
+          then do
+            let (# x #) = index# arr ix
+            acc2 <- f acc1 x
+            go (ix + 1) acc2
+          else pure acc1
+   in go 0 z0
+{-# INLINE foldlM' #-}
+
+-- | Strict left monadic fold over the elements of an array.
+ifoldlM' ::
+  (Contiguous arr, Element arr a, Monad m) =>
+  (b -> Int -> a -> m b) ->
+  b ->
+  arr a ->
+  m b
+ifoldlM' f z0 = \arr ->
+  let !sz = size arr
+      go !ix !acc1 =
+        if ix < sz
+          then do
+            let (# x #) = index# arr ix
+            acc2 <- f acc1 ix x
+            go (ix + 1) acc2
+          else pure acc1
+   in go 0 z0
+{-# INLINE ifoldlM' #-}
+
+-- | Drop elements that do not satisfy the predicate.
+filter ::
+  (Contiguous arr, Element arr a) =>
+  (a -> Bool) ->
+  arr a ->
+  arr a
+filter p arr = ifilter (const p) arr
+{-# INLINE filter #-}
+
+{- | Drop elements that do not satisfy the predicate which
+  is applied to values and their indices.
+-}
+ifilter ::
+  (Contiguous arr, Element arr a) =>
+  (Int -> a -> Bool) ->
+  arr a ->
+  arr a
+ifilter p arr = run $ do
+  marr :: MutablePrimArray s Word8 <- newPrimArray sz
+  let go1 :: Int -> Int -> ST s Int
+      go1 !ix !numTrue =
+        if ix < sz
+          then do
+            atIx <- indexM arr ix
+            let !keep = p ix atIx
+            let !keepTag = I# (dataToTag# keep)
+            writePrimArray marr ix (fromIntegral keepTag)
+            go1 (ix + 1) (numTrue + keepTag)
+          else pure numTrue
+  numTrue <- go1 0 0
+  if numTrue == sz
+    then pure arr
+    else do
+      marrTrues <- new numTrue
+      let go2 !ixSrc !ixDst = when (ixDst < numTrue) $ do
+            atIxKeep <- readPrimArray marr ixSrc
+            if isTrue atIxKeep
+              then do
+                atIxVal <- indexM arr ixSrc
+                write marrTrues ixDst atIxVal
+                go2 (ixSrc + 1) (ixDst + 1)
+              else go2 (ixSrc + 1) ixDst
+      go2 0 0
+      unsafeFreeze marrTrues
+ where
+  !sz = size arr
+{-# INLINE ifilter #-}
+
+{- | The 'mapMaybe' function is a version of 'map' which can throw out elements.
+  In particular, the functional arguments returns something of type @'Maybe' b@.
+  If this is 'Nothing', no element is added on to the result array. If it is
+  @'Just' b@, then @b@ is included in the result array.
+-}
+mapMaybe ::
+  forall arr1 arr2 a b.
+  ( Contiguous arr1
+  , Element arr1 a
+  , Contiguous arr2
+  , Element arr2 b
+  ) =>
+  (a -> Maybe b) ->
+  arr1 a ->
+  arr2 b
+mapMaybe f arr = run $ do
+  let !sz = size arr
+  let go :: Int -> Int -> [b] -> ST s ([b], Int)
+      go !ix !numJusts !justs =
+        if ix < sz
+          then do
+            atIx <- indexM arr ix
+            case f atIx of
+              Nothing -> go (ix + 1) numJusts justs
+              Just x -> go (ix + 1) (numJusts + 1) (x : justs)
+          else pure (justs, numJusts)
+  !(bs, !numJusts) <- go 0 0 []
+  !marr <- unsafeFromListReverseMutableN numJusts bs
+  unsafeFreeze marr
+{-# INLINE mapMaybe #-}
+
+{-# INLINE isTrue #-}
+isTrue :: Word8 -> Bool
+isTrue 0 = False
+isTrue _ = True
+
+{- | The 'catMaybes' function takes a list of 'Maybe's and returns a
+  list of all the 'Just' values.
+-}
+catMaybes ::
+  (Contiguous arr, Element arr a, Element arr (Maybe a)) =>
+  arr (Maybe a) ->
+  arr a
+catMaybes = mapMaybe id
+{-# INLINE catMaybes #-}
+
+-- | @'replicate' n x@ is an array of length @n@ with @x@ the value of every element.
+replicate :: (Contiguous arr, Element arr a) => Int -> a -> arr a
+replicate n x = create (replicateMut n x)
+{-# INLINE replicate #-}
+
+-- | @'replicateMutM' n act@ performs the action n times, gathering the results.
+replicateMutM ::
+  (PrimMonad m, Contiguous arr, Element arr a) =>
+  Int ->
+  m a ->
+  m (Mutable arr (PrimState m) a)
+replicateMutM len act = do
+  marr <- new len
+  let go !ix = when (ix < len) $ do
+        x <- act
+        write marr ix x
+        go (ix + 1)
+  go 0
+  pure marr
+{-# INLINE replicateMutM #-}
+
+{- | Create an array from a list. If the given length does
+not match the actual length, this function has undefined
+behavior.
+-}
+unsafeFromListN ::
+  (Contiguous arr, Element arr a) =>
+  -- | length of list
+  Int ->
+  -- | list
+  [a] ->
+  arr a
+unsafeFromListN n l = create (unsafeFromListMutableN n l)
+{-# INLINE unsafeFromListN #-}
+
+unsafeFromListMutableN ::
+  (Contiguous arr, Element arr a, PrimMonad m) =>
+  Int ->
+  [a] ->
+  m (Mutable arr (PrimState m) a)
+unsafeFromListMutableN n l = do
+  m <- new n
+  let go !_ [] = pure m
+      go !ix (x : xs) = do
+        write m ix x
+        go (ix + 1) xs
+  go 0 l
+{-# INLINE unsafeFromListMutableN #-}
+
+{- | Create a mutable array from a list, reversing the order of
+  the elements. If the given length does not match the actual length,
+  this function has undefined behavior.
+-}
+unsafeFromListReverseMutableN ::
+  (Contiguous arr, Element arr a, PrimMonad m) =>
+  Int ->
+  [a] ->
+  m (Mutable arr (PrimState m) a)
+unsafeFromListReverseMutableN n l = do
+  m <- new n
+  let go !_ [] = pure m
+      go !ix (x : xs) = do
+        write m ix x
+        go (ix - 1) xs
+  go (n - 1) l
+{-# INLINE unsafeFromListReverseMutableN #-}
+
+{- | Create an array from a list, reversing the order of the
+elements. If the given length does not match the actual length,
+this function has undefined behavior.
+-}
+unsafeFromListReverseN ::
+  (Contiguous arr, Element arr a) =>
+  Int ->
+  [a] ->
+  arr a
+unsafeFromListReverseN n l = create (unsafeFromListReverseMutableN n l)
+{-# INLINE unsafeFromListReverseN #-}
+
+-- | Map over a mutable array, modifying the elements in place.
+mapMutable ::
+  (Contiguous arr, Element arr a, PrimMonad m) =>
+  (a -> a) ->
+  Mutable arr (PrimState m) a ->
+  m ()
+mapMutable f !marr = do
+  !sz <- sizeMut marr
+  let go !ix = when (ix < sz) $ do
+        a <- read marr ix
+        write marr ix (f a)
+        go (ix + 1)
+  go 0
+{-# INLINE mapMutable #-}
+
+-- | Strictly map over a mutable array, modifying the elements in place.
+mapMutable' ::
+  (PrimMonad m, Contiguous arr, Element arr a) =>
+  (a -> a) ->
+  Mutable arr (PrimState m) a ->
+  m ()
+mapMutable' f !marr = do
+  !sz <- sizeMut marr
+  let go !ix = when (ix < sz) $ do
+        a <- read marr ix
+        let !b = f a
+        write marr ix b
+        go (ix + 1)
+  go 0
+{-# INLINE mapMutable' #-}
+
+-- | Map over a mutable array with indices, modifying the elements in place.
+imapMutable ::
+  (Contiguous arr, Element arr a, PrimMonad m) =>
+  (Int -> a -> a) ->
+  Mutable arr (PrimState m) a ->
+  m ()
+imapMutable f !marr = do
+  !sz <- sizeMut marr
+  let go !ix = when (ix < sz) $ do
+        a <- read marr ix
+        write marr ix (f ix a)
+        go (ix + 1)
+  go 0
+{-# INLINE imapMutable #-}
+
+-- | Strictly map over a mutable array with indices, modifying the elements in place.
+imapMutable' ::
+  (PrimMonad m, Contiguous arr, Element arr a) =>
+  (Int -> a -> a) ->
+  Mutable arr (PrimState m) a ->
+  m ()
+imapMutable' f !marr = do
+  !sz <- sizeMut marr
+  let go !ix = when (ix < sz) $ do
+        a <- read marr ix
+        let !b = f ix a
+        write marr ix b
+        go (ix + 1)
+  go 0
+{-# INLINE imapMutable' #-}
+
+{- | Map each element of the array to an action, evaluate these
+  actions from left to right, and collect the results in a
+  new array.
+-}
+traverseP ::
+  ( PrimMonad m
+  , Contiguous arr1
+  , Element arr1 a
+  , Contiguous arr2
+  , Element arr2 b
+  ) =>
+  (a -> m b) ->
+  arr1 a ->
+  m (arr2 b)
+traverseP f !arr = do
+  let !sz = size arr
+  !marr <- new sz
+  let go !ix = when (ix < sz) $ do
+        a <- indexM arr ix
+        b <- f a
+        write marr ix b
+        go (ix + 1)
+  go 0
+  unsafeFreeze marr
+{-# INLINE traverseP #-}
+
+{- | Map each element of the array to an action, evaluate these
+  actions from left to right, and collect the results in a
+  new array.
+-}
+itraverseP ::
+  ( PrimMonad m
+  , Contiguous arr1
+  , Element arr1 a
+  , Contiguous arr2
+  , Element arr2 b
+  ) =>
+  (Int -> a -> m b) ->
+  arr1 a ->
+  m (arr2 b)
+itraverseP f !arr = do
+  let !sz = size arr
+  !marr <- new sz
+  let go !ix = when (ix < sz) $ do
+        a <- indexM arr ix
+        b <- f ix a
+        write marr ix b
+        go (ix + 1)
+  go 0
+  unsafeFreeze marr
+{-# INLINE itraverseP #-}
+
+newtype STA v a = STA {_runSTA :: forall s. Mutable v s a -> ST s (v a)}
+
+runSTA :: (Contiguous v, Element v a) => Int -> STA v a -> v a
+runSTA !sz (STA m) = runST $ new sz >>= m
+{-# INLINE runSTA #-}
+
+{- | Map each element of the array to an action, evaluate these
+  actions from left to right, and collect the results.
+  For a version that ignores the results, see 'traverse_'.
+-}
+traverse ::
+  ( Contiguous arr1
+  , Contiguous arr2
+  , Element arr1 a
+  , Element arr2 b
+  , Applicative f
+  ) =>
+  (a -> f b) ->
+  arr1 a ->
+  f (arr2 b)
+traverse f = itraverse (const f)
+{-# INLINE traverse #-}
+
+{- | Map each element of the array to an action, evaluate these
+  actions from left to right, and ignore the results.
+  For a version that doesn't ignore the results, see 'traverse'.
+-}
+traverse_ ::
+  (Contiguous arr, Element arr a, Applicative f) =>
+  (a -> f b) ->
+  arr a ->
+  f ()
+traverse_ f = itraverse_ (const f)
+
+{- | Map each element of the array and its index to an action,
+  evaluating these actions from left to right.
+-}
+itraverse ::
+  ( Contiguous arr1
+  , Contiguous arr2
+  , Element arr1 a
+  , Element arr2 b
+  , Applicative f
+  ) =>
+  (Int -> a -> f b) ->
+  arr1 a ->
+  f (arr2 b)
+itraverse f = \arr ->
+  let !sz = size arr
+      go !ix =
+        if ix == sz
+          then pure (STA unsafeFreeze)
+          else case index# arr ix of
+            (# x #) ->
+              liftA2
+                ( \b (STA m) -> STA $ \marr -> do
+                    write marr ix b
+                    m marr
+                )
+                (f ix x)
+                (go (ix + 1))
+   in if sz == 0
+        then pure empty
+        else runSTA sz <$> go 0
+{-# INLINE itraverse #-}
+
+{- | Map each element of the array and its index to an action,
+  evaluate these actions from left to right, and ignore the results.
+  For a version that doesn't ignore the results, see 'itraverse'.
+-}
+itraverse_ ::
+  (Contiguous arr, Element arr a, Applicative f) =>
+  (Int -> a -> f b) ->
+  arr a ->
+  f ()
+itraverse_ f = \arr ->
+  let !sz = size arr
+      go !ix =
+        when (ix < sz) $
+          f ix (index arr ix) *> go (ix + 1)
+   in go 0
+{-# INLINE itraverse_ #-}
+
+{- | 'for' is 'traverse' with its arguments flipped. For a version
+  that ignores the results see 'for_'.
+-}
+for ::
+  ( Contiguous arr1
+  , Contiguous arr2
+  , Element arr1 a
+  , Element arr2 b
+  , Applicative f
+  ) =>
+  arr1 a ->
+  (a -> f b) ->
+  f (arr2 b)
+for = flip traverse
+{-# INLINE for #-}
+
+{- | 'for_' is 'traverse_' with its arguments flipped. For a version
+  that doesn't ignore the results see 'for'.
+
+  >>> for_ (C.fromList [1..4] :: PrimArray Int) print
+  1
+  2
+  3
+  4
+-}
+for_ ::
+  (Contiguous arr, Element arr a, Applicative f) =>
+  arr a ->
+  (a -> f b) ->
+  f ()
+for_ = flip traverse_
+{-# INLINE for_ #-}
+
+{- | Monadic accumulating strict left fold over the elements on an
+array.
+-}
+mapAccumLM' ::
+  ( Contiguous arr1
+  , Contiguous arr2
+  , Element arr1 b
+  , Element arr2 c
+  , Monad m
+  ) =>
+  (a -> b -> m (a, c)) ->
+  a ->
+  arr1 b ->
+  m (a, arr2 c)
+{-# INLINE mapAccumLM' #-}
+mapAccumLM' f a0 src = go 0 [] a0
+ where
+  !sz = size src
+  go !ix !xs !acc =
+    if ix < sz
+      then do
+        (!acc', !x) <- f acc (index src ix)
+        go (ix + 1) (x : xs) acc'
+      else
+        let !xs' = unsafeFromListReverseN sz xs
+         in pure (acc, xs')
+
+mapAccum' ::
+  forall arr1 arr2 a b c.
+  ( Contiguous arr1
+  , Contiguous arr2
+  , Element arr1 b
+  , Element arr2 c
+  , Monoid a
+  ) =>
+  (b -> (a, c)) ->
+  arr1 b ->
+  (a, arr2 c)
+{-# INLINE mapAccum' #-}
+mapAccum' f !src = runST $ do
+  dst <- new sz
+  acc <- go 0 dst mempty
+  dst' <- unsafeFreeze dst
+  pure (acc, dst')
+ where
+  !sz = size src
+  go :: Int -> Mutable arr2 s c -> a -> ST s a
+  go !ix !dst !accA =
+    if ix < sz
+      then do
+        let (!accB, !x) = f (index src ix)
+        write dst ix x
+        go (ix + 1) dst (accA <> accB)
+      else pure accA
+
+{- | Map each element of a structure to a monadic action,
+  evaluate these actions from left to right, and collect
+  the results. for a version that ignores the results see
+  'mapM_'.
+-}
+mapM ::
+  ( Contiguous arr1
+  , Contiguous arr2
+  , Element arr1 a
+  , Element arr2 b
+  , Monad m
+  ) =>
+  (a -> m b) ->
+  arr1 a ->
+  m (arr2 b)
+mapM f arr =
+  let !sz = size arr
+   in generateM sz $ \ix -> indexM arr ix >>= f
+{-# INLINE mapM #-}
+
+{- | Map each element of a structure to a monadic action,
+  evaluate these actions from left to right, and ignore
+  the results. For a version that doesn't ignore the results
+  see 'mapM'.
+
+  'mapM_' = 'traverse_'
+-}
+mapM_ ::
+  (Contiguous arr, Element arr a, Element arr b, Applicative f) =>
+  (a -> f b) ->
+  arr a ->
+  f ()
+mapM_ = traverse_
+{-# INLINE mapM_ #-}
+
+{- | 'forM' is 'mapM' with its arguments flipped. For a version that
+  ignores its results, see 'forM_'.
+-}
+forM ::
+  ( Contiguous arr1
+  , Contiguous arr2
+  , Element arr1 a
+  , Element arr2 b
+  , Monad m
+  ) =>
+  arr1 a ->
+  (a -> m b) ->
+  m (arr2 b)
+forM = flip mapM
+{-# INLINE forM #-}
+
+{- | 'forM_' is 'mapM_' with its arguments flipped. For a version that
+  doesn't ignore its results, see 'forM'.
+-}
+forM_ ::
+  (Contiguous arr, Element arr a, Element arr b, Applicative f) =>
+  arr a ->
+  (a -> f b) ->
+  f ()
+forM_ = flip traverse_
+{-# INLINE forM_ #-}
+
+{- | Evaluate each action in the structure from left to right
+  and collect the results. For a version that ignores the
+  results see 'sequence_'.
+-}
+sequence ::
+  ( Contiguous arr1
+  , Contiguous arr2
+  , Element arr1 (f a)
+  , Element arr2 a
+  , Applicative f
+  ) =>
+  arr1 (f a) ->
+  f (arr2 a)
+sequence = traverse id
+{-# INLINE sequence #-}
+
+{- | Evaluate each action in the structure from left to right
+  and ignore the results. For a version that doesn't ignore
+  the results see 'sequence'.
+-}
+sequence_ ::
+  ( Contiguous arr
+  , Element arr (f a)
+  , Applicative f
+  ) =>
+  arr (f a) ->
+  f ()
+sequence_ = foldr (*>) (pure ())
+{-# INLINE sequence_ #-}
+
+{- | The sum of a collection of actions, generalizing 'concat'.
+
+  >>> asum (C.fromList ['Just' "Hello", 'Nothing', Just "World"] :: Array String)
+  Just "Hello"
+-}
+asum ::
+  ( Contiguous arr
+  , Element arr (f a)
+  , A.Alternative f
+  ) =>
+  arr (f a) ->
+  f a
+asum = foldr (A.<|>) A.empty
+{-# INLINE asum #-}
+
+{- | Construct an array of the given length by applying
+  the function to each index.
+-}
+generate ::
+  (Contiguous arr, Element arr a) =>
+  Int ->
+  (Int -> a) ->
+  arr a
+generate len f = create (generateMutable len f)
+{-# INLINE generate #-}
+
+{- | Construct an array of the given length by applying
+  the monadic action to each index.
+-}
+generateM ::
+  (Contiguous arr, Element arr a, Monad m) =>
+  Int ->
+  (Int -> m a) ->
+  m (arr a)
+{-# INLINE generateM #-}
+generateM !sz f =
+  let go !ix =
+        if ix < sz
+          then
+            liftA2
+              ( \b (STA m) -> STA $ \marr -> do
+                  write marr ix b
+                  m marr
+              )
+              (f ix)
+              (go (ix + 1))
+          else pure $ STA unsafeFreeze
+   in if sz == 0
+        then pure empty
+        else runSTA sz <$> go 0
+
+{- | Construct a mutable array of the given length by applying
+  the function to each index.
+-}
+generateMutable ::
+  (Contiguous arr, Element arr a, PrimMonad m) =>
+  Int ->
+  (Int -> a) ->
+  m (Mutable arr (PrimState m) a)
+generateMutable len f = generateMutableM len (pure . f)
+{-# INLINE generateMutable #-}
+
+{- | Construct a mutable array of the given length by applying
+  the monadic action to each index.
+-}
+generateMutableM ::
+  (Contiguous arr, Element arr a, PrimMonad m) =>
+  Int ->
+  (Int -> m a) ->
+  m (Mutable arr (PrimState m) a)
+generateMutableM !len f = do
+  marr <- new len
+  let go !ix = when (ix < len) $ do
+        x <- f ix
+        write marr ix x
+        go (ix + 1)
+  go 0
+  pure marr
+{-# INLINE generateMutableM #-}
+
+{- | Apply a function @n@ times to a value and construct an array
+  where each consecutive element is the result of an additional
+  application of this function. The zeroth element is the original value.
+
+  @'iterateN' 5 ('+' 1) 0 = 'fromListN' 5 [0,1,2,3,4]@
+-}
+iterateN ::
+  (Contiguous arr, Element arr a) =>
+  Int ->
+  (a -> a) ->
+  a ->
+  arr a
+iterateN len f z0 = runST (iterateMutableN len f z0 >>= unsafeFreeze)
+{-# INLINE iterateN #-}
+
+{- | Apply a function @n@ times to a value and construct a mutable array
+  where each consecutive element is the result of an additional
+  application of this function. The zeroth element is the original value.
+-}
+iterateMutableN ::
+  (Contiguous arr, Element arr a, PrimMonad m) =>
+  Int ->
+  (a -> a) ->
+  a ->
+  m (Mutable arr (PrimState m) a)
+iterateMutableN len f z0 = iterateMutableNM len (pure . f) z0
+{-# INLINE iterateMutableN #-}
+
+{- | Apply a monadic function @n@ times to a value and construct a mutable array
+  where each consecutive element is the result of an additional
+  application of this function. The zeroth element is the original value.
+-}
+iterateMutableNM ::
+  (Contiguous arr, Element arr a, PrimMonad m) =>
+  Int ->
+  (a -> m a) ->
+  a ->
+  m (Mutable arr (PrimState m) a)
+iterateMutableNM !len f z0 = do
+  marr <- new len
+  -- we are strict in the accumulator because
+  -- otherwise we could build up a ton of `f (f (f (f .. (f a))))`
+  -- thunks for no reason.
+  let go !ix !acc
+        | ix <= 0 = write marr ix z0 >> go (ix + 1) z0
+        | ix == len = pure ()
+        | otherwise = do
+            a <- f acc
+            write marr ix a
+            go (ix + 1) a
+  go 0 z0
+  pure marr
+{-# INLINE iterateMutableNM #-}
+
+-- | Execute the monad action and freeze the resulting array.
+create ::
+  (Contiguous arr, Element arr a) =>
+  (forall s. ST s (Mutable arr s a)) ->
+  arr a
+create x = run (unsafeFreeze =<< x)
+{-# INLINE create #-}
+
+-- | Execute the monadic action and freeze the resulting array.
+createT ::
+  (Contiguous arr, Element arr a, Traversable f) =>
+  (forall s. ST s (f (Mutable arr s a))) ->
+  f (arr a)
+createT p = runST (Prelude.mapM unsafeFreeze =<< p)
+{-# INLINE createT #-}
+
+{- | Construct an array by repeatedly applying a generator
+  function to a seed. The generator function yields 'Just' the
+  next element and the new seed or 'Nothing' if there are no more
+  elements.
+
+>>> unfoldr (\n -> if n == 0 then Nothing else Just (n,n-1) 10
+    <10,9,8,7,6,5,4,3,2,1>
+-}
+
+-- Unfortunately, because we don't know ahead of time when to stop,
+-- we need to construct a list and then turn it into an array.
+unfoldr ::
+  (Contiguous arr, Element arr a) =>
+  (b -> Maybe (a, b)) ->
+  b ->
+  arr a
+unfoldr f z0 = create (unfoldrMutable f z0)
+{-# INLINE unfoldr #-}
+
+{- | Construct a mutable array by repeatedly applying a generator
+  function to a seed. The generator function yields 'Just' the
+  next element and the new seed or 'Nothing' if there are no more
+  elements.
+
+>>> unfoldrMutable (\n -> if n == 0 then Nothing else Just (n,n-1) 10
+    <10,9,8,7,6,5,4,3,2,1>
+-}
+
+-- Unfortunately, because we don't know ahead of time when to stop,
+-- we need to construct a list and then turn it into an array.
+unfoldrMutable ::
+  (Contiguous arr, Element arr a, PrimMonad m) =>
+  (b -> Maybe (a, b)) ->
+  b ->
+  m (Mutable arr (PrimState m) a)
+unfoldrMutable f z0 = do
+  let go !sz s !xs = case f s of
+        Nothing -> pure (sz, xs)
+        Just (x, s') -> go (sz + 1) s' (x : xs)
+  (sz, xs) <- go 0 z0 []
+  unsafeFromListReverseMutableN sz xs
+{-# INLINE unfoldrMutable #-}
+
+{- | Construct an array with at most n elements by repeatedly
+  applying the generator function to a seed. The generator function
+  yields 'Just' the next element and the new seed or 'Nothing' if
+  there are no more elements.
+-}
+unfoldrN ::
+  (Contiguous arr, Element arr a) =>
+  Int ->
+  (b -> Maybe (a, b)) ->
+  b ->
+  arr a
+unfoldrN maxSz f z0 = create (unfoldrMutableN maxSz f z0)
+{-# INLINE unfoldrN #-}
+
+{- | Construct a mutable array with at most n elements by repeatedly
+  applying the generator function to a seed. The generator function
+  yields 'Just' the next element and the new seed or 'Nothing' if
+  there are no more elements.
+-}
+unfoldrMutableN ::
+  (Contiguous arr, Element arr a, PrimMonad m) =>
+  Int ->
+  (b -> Maybe (a, b)) ->
+  b ->
+  m (Mutable arr (PrimState m) a)
+unfoldrMutableN !maxSz f z0 = do
+  m <- new maxSz
+  let go !ix s =
+        if ix < maxSz
+          then case f s of
+            Nothing -> pure ix
+            Just (x, s') -> do
+              write m ix x
+              go (ix + 1) s'
+          else pure ix
+  sz <- go 0 z0
+  shrink m sz
+{-# INLINE unfoldrMutableN #-}
+
+-- | Convert an array to a list.
+toList ::
+  (Contiguous arr, Element arr a) =>
+  arr a ->
+  [a]
+toList arr = build (\c n -> foldr c n arr)
+{-# INLINE toList #-}
+
+-- | Convert a mutable array to a list.
+
+-- I don't think this can be expressed in terms of foldr/build,
+-- so we just loop through the array.
+toListMutable ::
+  (Contiguous arr, Element arr a, PrimMonad m) =>
+  Mutable arr (PrimState m) a ->
+  m [a]
+toListMutable marr = do
+  sz <- sizeMut marr
+  let go !ix !acc =
+        if ix >= 0
+          then do
+            x <- read marr ix
+            go (ix - 1) (x : acc)
+          else pure acc
+  go (sz - 1) []
+{-# INLINE toListMutable #-}
+
+{- | Given an 'Int' that is representative of the length of
+  the list, convert the list into a mutable array of the
+  given length.
+
+  /Note/: calls 'error' if the given length is incorrect.
+-}
+fromListMutableN ::
+  (Contiguous arr, Element arr a, PrimMonad m) =>
+  Int ->
+  [a] ->
+  m (Mutable arr (PrimState m) a)
+fromListMutableN len vs = do
+  marr <- new len
+  let go [] !ix =
+        if ix == len
+          then pure ()
+          else error "Data.Primitive.Contiguous.fromListN: list length less than specified size."
+      go (a : as) !ix =
+        if ix < len
+          then do
+            write marr ix a
+            go as (ix + 1)
+          else error "Data.Primitive.Contiguous.fromListN: list length greater than specified size."
+  go vs 0
+  pure marr
+{-# INLINE fromListMutableN #-}
+
+-- | Convert a list into a mutable array of the given length.
+fromListMutable ::
+  (Contiguous arr, Element arr a, PrimMonad m) =>
+  [a] ->
+  m (Mutable arr (PrimState m) a)
+fromListMutable xs = fromListMutableN (length xs) xs
+{-# INLINE fromListMutable #-}
+
+{- | Given an 'Int' that is representative of the length of
+  the list, convert the list into a mutable array of the
+  given length.
+
+  /Note/: calls 'error' if the given length is incorrect.
+-}
+fromListN ::
+  (Contiguous arr, Element arr a) =>
+  Int ->
+  [a] ->
+  arr a
+fromListN len vs = create (fromListMutableN len vs)
+{-# INLINE fromListN #-}
+
+-- | Convert a list into an array.
+fromList ::
+  (Contiguous arr, Element arr a) =>
+  [a] ->
+  arr a
+fromList vs = create (fromListMutable vs)
+{-# INLINE fromList #-}
+
+-- | Modify the elements of a mutable array in-place.
+modify ::
+  (Contiguous arr, Element arr a, PrimMonad m) =>
+  (a -> a) ->
+  Mutable arr (PrimState m) a ->
+  m ()
+modify f marr = do
+  !sz <- sizeMut marr
+  let go !ix = when (ix < sz) $ do
+        x <- read marr ix
+        write marr ix (f x)
+        go (ix + 1)
+  go 0
+{-# INLINE modify #-}
+
+-- | Strictly modify the elements of a mutable array in-place.
+modify' ::
+  (Contiguous arr, Element arr a, PrimMonad m) =>
+  (a -> a) ->
+  Mutable arr (PrimState m) a ->
+  m ()
+modify' f marr = do
+  !sz <- sizeMut marr
+  let go !ix = when (ix < sz) $ do
+        x <- read marr ix
+        let !y = f x
+        write marr ix y
+        go (ix + 1)
+  go 0
+{-# INLINE modify' #-}
+
+{- | Yield an array of the given length containing the values
+  @x, 'succ' x, 'succ' ('succ' x)@ etc.
+-}
+enumFromN ::
+  (Contiguous arr, Element arr a, Enum a) =>
+  a ->
+  Int ->
+  arr a
+enumFromN z0 sz = create (enumFromMutableN z0 sz)
+{-# INLINE enumFromN #-}
+
+{- | Yield a mutable array of the given length containing the values
+  @x, 'succ' x, 'succ' ('succ' x)@ etc.
+-}
+enumFromMutableN ::
+  (Contiguous arr, Element arr a, PrimMonad m, Enum a) =>
+  a ->
+  Int ->
+  m (Mutable arr (PrimState m) a)
+enumFromMutableN z0 !sz = do
+  m <- new sz
+  let go !ix z =
+        if ix < sz
+          then do
+            write m ix z
+            go (ix + 1) (succ z)
+          else pure m
+  go 0 z0
+{-# INLINE enumFromMutableN #-}
+
+{- | Lift an accumulating hash function over the elements of the array,
+  returning the final accumulated hash.
+-}
+liftHashWithSalt ::
+  (Contiguous arr, Element arr a) =>
+  (Int -> a -> Int) ->
+  Int ->
+  arr a ->
+  Int
+liftHashWithSalt f s0 arr = go 0 s0
+ where
+  sz = size arr
+  go !ix !s =
+    if ix < sz
+      then
+        let !(# x #) = index# arr ix
+         in go (ix + 1) (f s x)
+      else hashIntWithSalt s ix
+{-# INLINE liftHashWithSalt #-}
+
+-- | Reverse the elements of an array.
+reverse ::
+  (Contiguous arr, Element arr a) =>
+  arr a ->
+  arr a
+reverse arr = run $ do
+  marr <- new (size arr)
+  copy marr 0 (toSlice arr)
+  reverseMutable marr
+  unsafeFreeze marr
+{-# INLINE reverse #-}
+
+-- | Reverse the elements of a mutable array, in-place.
+reverseMutable ::
+  (Contiguous arr, Element arr a, PrimMonad m) =>
+  Mutable arr (PrimState m) a ->
+  m ()
+reverseMutable marr = do
+  !sz <- sizeMut marr
+  reverseSlice marr 0 (sz - 1)
+{-# INLINE reverseMutable #-}
+
+-- | Reverse the elements of a slice of a mutable array, in-place.
+reverseSlice ::
+  (Contiguous arr, Element arr a, PrimMonad m) =>
+  Mutable arr (PrimState m) a ->
+  -- | start index
+  Int ->
+  -- | end index
+  Int ->
+  m ()
+reverseSlice !marr !start !end = do
+  let go !s !e =
+        if s >= e
+          then pure ()
+          else do
+            tmp <- read marr s
+            write marr s =<< read marr e
+            write marr e tmp
+            go (s + 1) (e - 1)
+  go start end
+{-# INLINE reverseSlice #-}
+
+{- | This function does not behave deterministically. Optimization level and
+inlining can affect its results. However, the one thing that can be counted
+on is that if it returns 'True', the two immutable arrays are definitely the
+same. This is useful as shortcut for equality tests. However, keep in mind
+that a result of 'False' tells us nothing about the arguments.
+-}
+same :: (ContiguousU arr) => arr a -> arr a -> Bool
+same a b =
+  isTrue#
+    ( sameMutableArrayArray#
+        (unsafeCoerce# (unlift a) :: MutableArrayArray# s)
+        (unsafeCoerce# (unlift b) :: MutableArrayArray# s)
+    )
+
+hashIntWithSalt :: Int -> Int -> Int
+hashIntWithSalt salt x = salt `combine` x
+{-# INLINE hashIntWithSalt #-}
+
+combine :: Int -> Int -> Int
+combine h1 h2 = (h1 * 16777619) `xor` h2
+{-# INLINE combine #-}
+
+-- | Does the element occur in the structure?
+elem :: (Contiguous arr, Element arr a, Eq a) => a -> arr a -> Bool
+elem a !arr =
+  let !sz = size arr
+      go !ix
+        | ix < sz = case index# arr ix of
+            !(# x #) ->
+              if a == x
+                then True
+                else go (ix + 1)
+        | otherwise = False
+   in go 0
+{-# INLINE elem #-}
+
+-- | The largest element of a structure.
+maximum :: (Contiguous arr, Element arr a, Ord a) => arr a -> Maybe a
+maximum = maximumBy compare
+{-# INLINE maximum #-}
+
+-- | The least element of a structure.
+minimum :: (Contiguous arr, Element arr a, Ord a) => arr a -> Maybe a
+minimum = minimumBy compare
+{-# INLINE minimum #-}
+
+{- | The largest element of a structure with respect to the
+  given comparison function.
+-}
+maximumBy ::
+  (Contiguous arr, Element arr a) =>
+  (a -> a -> Ordering) ->
+  arr a ->
+  Maybe a
+maximumBy f arr =
+  let !sz = size arr
+      go !ix o =
+        if ix < sz
+          then case index# arr ix of
+            !(# x #) -> go (ix + 1) (case f x o of GT -> x; _ -> o)
+          else o
+   in if sz == 0
+        then Nothing
+        else Just (go 0 (index arr 0))
+{-# INLINE maximumBy #-}
+
+{- | The least element of a structure with respect to the
+  given comparison function.
+-}
+minimumBy ::
+  (Contiguous arr, Element arr a) =>
+  (a -> a -> Ordering) ->
+  arr a ->
+  Maybe a
+minimumBy f arr =
+  let !sz = size arr
+      go !ix o =
+        if ix < sz
+          then case index# arr ix of
+            !(# x #) -> go (ix + 1) (case f x o of GT -> o; _ -> x)
+          else o
+   in if sz == 0
+        then Nothing
+        else Just (go 0 (index arr 0))
+{-# INLINE minimumBy #-}
+
+{- | 'find' takes a predicate and an array, and returns the leftmost
+  element of the array matching the prediate, or 'Nothing' if there
+  is no such element.
+-}
+find ::
+  (Contiguous arr, Element arr a) =>
+  (a -> Bool) ->
+  arr a ->
+  Maybe a
+find p = coerce . (foldMap (\x -> if p x then Just (First x) else Nothing))
+{-# INLINE find #-}
+
+{- | 'findIndex' takes a predicate and an array, and returns the index of
+  the leftmost element of the array matching the prediate, or 'Nothing'
+  if there is no such element.
+-}
+findIndex ::
+  (Contiguous arr, Element arr a) =>
+  (a -> Bool) ->
+  arr a ->
+  Maybe Int
+findIndex p xs = loop 0
+ where
+  loop i
+    | i < size xs = if p (index xs i) then Just i else loop (i + 1)
+    | otherwise = Nothing
+{-# INLINE findIndex #-}
+
+-- | Swap the elements of the mutable array at the given indices.
+swap ::
+  (Contiguous arr, Element arr a, PrimMonad m) =>
+  Mutable arr (PrimState m) a ->
+  Int ->
+  Int ->
+  m ()
+swap !marr !ix1 !ix2 = do
+  atIx1 <- read marr ix1
+  atIx2 <- read marr ix2
+  write marr ix1 atIx2
+  write marr ix2 atIx1
+{-# INLINE swap #-}
+
+{- | Extracts from an array of 'Either' all the 'Left' elements.
+All the 'Left' elements are extracted in order.
+-}
+lefts ::
+  forall arr a b.
+  ( Contiguous arr
+  , Element arr a
+  , Element arr (Either a b)
+  ) =>
+  arr (Either a b) ->
+  arr a
+lefts !arr = create $ do
+  let !sz = size arr
+      go :: Int -> [a] -> Int -> ST s (Int, [a])
+      go !ix !as !acc =
+        if ix < sz
+          then do
+            indexM arr ix >>= \case
+              Left a -> go (ix + 1) (a : as) (acc + 1)
+              Right _ -> go (ix + 1) as acc
+          else pure (acc, as)
+  (len, as) <- go 0 [] 0
+  unsafeFromListReverseMutableN len as
+{-# INLINE lefts #-}
+
+{- | Extracts from an array of 'Either' all the 'Right' elements.
+All the 'Right' elements are extracted in order.
+-}
+rights ::
+  forall arr a b.
+  ( Contiguous arr
+  , Element arr b
+  , Element arr (Either a b)
+  ) =>
+  arr (Either a b) ->
+  arr b
+rights !arr = create $ do
+  let !sz = size arr
+      go :: Int -> [b] -> Int -> ST s (Int, [b])
+      go !ix !bs !acc =
+        if ix < sz
+          then do
+            indexM arr ix >>= \case
+              Left _ -> go (ix + 1) bs acc
+              Right b -> go (ix + 1) (b : bs) (acc + 1)
+          else pure (acc, bs)
+  (len, bs) <- go 0 [] 0
+  unsafeFromListReverseMutableN len bs
+{-# INLINE rights #-}
+
+{- | Partitions an array of 'Either' into two arrays.
+All the 'Left' elements are extracted, in order, to the first
+component of the output. Similarly the 'Right' elements are extracted
+to the second component of the output.
+-}
+partitionEithers ::
+  forall arr a b.
+  ( Contiguous arr
+  , Element arr a
+  , Element arr b
+  , Element arr (Either a b)
+  ) =>
+  arr (Either a b) ->
+  (arr a, arr b)
+partitionEithers !arr = runST $ do
+  let !sz = size arr
+      go :: Int -> [a] -> [b] -> Int -> Int -> ST s (Int, Int, [a], [b])
+      go !ix !as !bs !accA !accB =
+        if ix < sz
+          then do
+            indexM arr ix >>= \case
+              Left a -> go (ix + 1) (a : as) bs (accA + 1) accB
+              Right b -> go (ix + 1) as (b : bs) accA (accB + 1)
+          else pure (accA, accB, as, bs)
+  (lenA, lenB, as, bs) <- go 0 [] [] 0 0
+  arrA <- unsafeFreeze =<< unsafeFromListReverseMutableN lenA as
+  arrB <- unsafeFreeze =<< unsafeFromListReverseMutableN lenB bs
+  pure (arrA, arrB)
+{-# INLINE partitionEithers #-}
+
+{- | 'scanl' is similar to 'foldl', but returns an array of
+  successive reduced values from the left:
+
+  > scanl f z [x1, x2, ...] = [z, f z x1, f (f z x1) x2, ...]
+
+  Note that
+
+  > last (toList (scanl f z xs)) == foldl f z xs.
+-}
+scanl ::
+  ( Contiguous arr1
+  , Contiguous arr2
+  , Element arr1 a
+  , Element arr2 b
+  ) =>
+  (b -> a -> b) ->
+  b ->
+  arr1 a ->
+  arr2 b
+scanl f = iscanl (const f)
+{-# INLINE scanl #-}
+
+{- | A variant of 'scanl' whose function argument takes the current
+  index as an argument.
+-}
+iscanl ::
+  ( Contiguous arr1
+  , Contiguous arr2
+  , Element arr1 a
+  , Element arr2 b
+  ) =>
+  (Int -> b -> a -> b) ->
+  b ->
+  arr1 a ->
+  arr2 b
+iscanl f q as = internalScanl (size as + 1) f q as
+{-# INLINE iscanl #-}
+
+-- | A strictly accumulating version of 'scanl'.
+scanl' ::
+  ( Contiguous arr1
+  , Contiguous arr2
+  , Element arr1 a
+  , Element arr2 b
+  ) =>
+  (b -> a -> b) ->
+  b ->
+  arr1 a ->
+  arr2 b
+scanl' f = iscanl' (const f)
+{-# INLINE scanl' #-}
+
+-- | A strictly accumulating version of 'iscanl'.
+iscanl' ::
+  ( Contiguous arr1
+  , Contiguous arr2
+  , Element arr1 a
+  , Element arr2 b
+  ) =>
+  (Int -> b -> a -> b) ->
+  b ->
+  arr1 a ->
+  arr2 b
+iscanl' f !q as = internalScanl' (size as + 1) f q as
+{-# INLINE iscanl' #-}
+
+-- Internal only. The first argument is the size of the array
+-- argument. This function helps prevent duplication.
+internalScanl ::
+  ( Contiguous arr1
+  , Contiguous arr2
+  , Element arr1 a
+  , Element arr2 b
+  ) =>
+  Int ->
+  (Int -> b -> a -> b) ->
+  b ->
+  arr1 a ->
+  arr2 b
+internalScanl !sz f !q as = create $ do
+  !marr <- new sz
+  let go !ix acc = when (ix < sz) $ do
+        write marr ix acc
+        x <- indexM as ix
+        go (ix + 1) (f ix acc x)
+  go 0 q
+  pure marr
+{-# INLINE internalScanl #-}
+
+-- Internal only. The first argument is the size of the array
+-- argument. This function helps prevent duplication.
+internalScanl' ::
+  ( Contiguous arr1
+  , Contiguous arr2
+  , Element arr1 a
+  , Element arr2 b
+  ) =>
+  Int ->
+  (Int -> b -> a -> b) ->
+  b ->
+  arr1 a ->
+  arr2 b
+internalScanl' !sz f !q as = create $ do
+  !marr <- new sz
+  let go !ix !acc = when (ix < sz) $ do
+        write marr ix acc
+        x <- indexM as ix
+        go (ix + 1) (f ix acc x)
+  go 0 q
+  pure marr
+{-# INLINE internalScanl' #-}
+
+{- | A prescan.
+
+  @prescanl f z = init . scanl f z@
+
+  Example: @prescanl (+) 0 \<1,2,3,4\> = \<0,1,3,6\>@
+-}
+prescanl ::
+  ( Contiguous arr1
+  , Contiguous arr2
+  , Element arr1 a
+  , Element arr2 b
+  ) =>
+  (b -> a -> b) ->
+  b ->
+  arr1 a ->
+  arr2 b
+prescanl f = iprescanl (const f)
+{-# INLINE prescanl #-}
+
+{- | A variant of 'prescanl' where the function argument takes
+  the current index of the array as an additional argument.
+-}
+iprescanl ::
+  ( Contiguous arr1
+  , Contiguous arr2
+  , Element arr1 a
+  , Element arr2 b
+  ) =>
+  (Int -> b -> a -> b) ->
+  b ->
+  arr1 a ->
+  arr2 b
+iprescanl f q as = internalScanl (size as) f q as
+{-# INLINE iprescanl #-}
+
+-- | Like 'prescanl', but with a strict accumulator.
+prescanl' ::
+  ( Contiguous arr1
+  , Contiguous arr2
+  , Element arr1 a
+  , Element arr2 b
+  ) =>
+  (b -> a -> b) ->
+  b ->
+  arr1 a ->
+  arr2 b
+prescanl' f = iprescanl (const f)
+{-# INLINE prescanl' #-}
+
+-- | Like 'iprescanl', but with a strict accumulator.
+iprescanl' ::
+  ( Contiguous arr1
+  , Contiguous arr2
+  , Element arr1 a
+  , Element arr2 b
+  ) =>
+  (Int -> b -> a -> b) ->
+  b ->
+  arr1 a ->
+  arr2 b
+iprescanl' f !q as = internalScanl' (size as) f q as
+{-# INLINE iprescanl' #-}
+
+{- | 'zipWith' generalises 'zip' by zipping with the function
+  given as the first argument, instead of a tupling function.
+  For example, 'zipWith' (+) is applied to two arrays to produce
+  an array of the corresponding sums.
+-}
+zipWith ::
+  ( Contiguous arr1
+  , Contiguous arr2
+  , Contiguous arr3
+  , Element arr1 a
+  , Element arr2 b
+  , Element arr3 c
+  ) =>
+  (a -> b -> c) ->
+  arr1 a ->
+  arr2 b ->
+  arr3 c
+zipWith f = izipWith (\_ a b -> f a b)
+{-# INLINE zipWith #-}
+
+-- | Variant of 'zipWith' that provides the index of each pair of elements.
+izipWith ::
+  ( Contiguous arr1
+  , Contiguous arr2
+  , Contiguous arr3
+  , Element arr1 a
+  , Element arr2 b
+  , Element arr3 c
+  ) =>
+  (Int -> a -> b -> c) ->
+  arr1 a ->
+  arr2 b ->
+  arr3 c
+izipWith f as bs = create $ do
+  let !sz = min (size as) (size bs)
+  !marr <- new sz
+  let go !ix = when (ix < sz) $ do
+        a <- indexM as ix
+        b <- indexM bs ix
+        let !g = f ix a b
+        write marr ix g
+        go (ix + 1)
+  go 0
+  pure marr
+{-# INLINE izipWith #-}
+
+{- | Variant of 'zipWith' that accepts an accumulator, performing a lazy
+right fold over both arrays.
+-}
+foldrZipWith ::
+  ( Contiguous arr1
+  , Contiguous arr2
+  , Element arr1 a
+  , Element arr2 b
+  ) =>
+  (a -> b -> c -> c) ->
+  c ->
+  arr1 a ->
+  arr2 b ->
+  c
+foldrZipWith f = ifoldrZipWith (\_ x y c -> f x y c)
+{-# INLINE foldrZipWith #-}
+
+{- | Variant of 'zipWith' that accepts an accumulator, performing a strict
+left monadic fold over both arrays.
+-}
+foldlZipWithM' ::
+  ( Contiguous arr1
+  , Contiguous arr2
+  , Element arr1 a
+  , Element arr2 b
+  , Monad m
+  ) =>
+  (c -> a -> b -> m c) ->
+  c ->
+  arr1 a ->
+  arr2 b ->
+  m c
+foldlZipWithM' f = ifoldlZipWithM' (\_ x y c -> f x y c)
+{-# INLINE foldlZipWithM' #-}
+
+-- | Variant of 'foldrZipWith' that provides the index of each pair of elements.
+ifoldrZipWith ::
+  ( Contiguous arr1
+  , Contiguous arr2
+  , Element arr1 a
+  , Element arr2 b
+  ) =>
+  (Int -> a -> b -> c -> c) ->
+  c ->
+  arr1 a ->
+  arr2 b ->
+  c
+ifoldrZipWith f z = \arr1 arr2 ->
+  let !sz = min (size arr1) (size arr2)
+      go !ix =
+        if sz > ix
+          then case index# arr1 ix of
+            (# x #) -> case index# arr2 ix of
+              (# y #) -> f ix x y (go (ix + 1))
+          else z
+   in go 0
+{-# INLINE ifoldrZipWith #-}
+
+foldlZipWith' ::
+  ( Contiguous arr1
+  , Contiguous arr2
+  , Element arr1 a
+  , Element arr2 b
+  ) =>
+  (c -> a -> b -> c) ->
+  c ->
+  arr1 a ->
+  arr2 b ->
+  c
+foldlZipWith' f = ifoldlZipWith' (\_ x y c -> f x y c)
+{-# INLINE foldlZipWith' #-}
+
+ifoldlZipWith' ::
+  ( Contiguous arr1
+  , Contiguous arr2
+  , Element arr1 a
+  , Element arr2 b
+  ) =>
+  (Int -> c -> a -> b -> c) ->
+  c ->
+  arr1 a ->
+  arr2 b ->
+  c
+ifoldlZipWith' f !z !arr1 !arr2 =
+  let !sz = min (size arr1) (size arr2)
+      go !ix !acc =
+        if ix == sz
+          then acc
+          else case index# arr1 ix of
+            (# x #) -> case index# arr2 ix of
+              (# y #) -> go (ix + 1) (f ix acc x y)
+   in go 0 z
+{-# INLINE ifoldlZipWith' #-}
+
+-- | Variant of 'foldlZipWithM\'' that provides the index of each pair of elements.
+ifoldlZipWithM' ::
+  ( Contiguous arr1
+  , Contiguous arr2
+  , Element arr1 a
+  , Element arr2 b
+  , Monad m
+  ) =>
+  (Int -> c -> a -> b -> m c) ->
+  c ->
+  arr1 a ->
+  arr2 b ->
+  m c
+ifoldlZipWithM' f z = \arr1 arr2 ->
+  let !sz = min (size arr1) (size arr2)
+      go !ix !acc =
+        if sz > ix
+          then case index# arr1 ix of
+            (# x #) -> case index# arr2 ix of
+              (# y #) -> do
+                acc' <- f ix acc x y
+                go (ix + 1) acc'
+          else pure acc
+   in go 0 z
+{-# INLINE ifoldlZipWithM' #-}
+
+{- | 'zip' takes two arrays and returns an array of
+  corresponding pairs.
+
+  > zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]
+
+  If one input array is shorter than the other, excess
+  elements of the longer array are discarded:
+
+  > zip [1] ['a', 'b'] = [(1, 'a')]
+  > zip [1, 2] ['a'] = [(1, 'a')]
+-}
+zip ::
+  ( Contiguous arr1
+  , Contiguous arr2
+  , Contiguous arr3
+  , Element arr1 a
+  , Element arr2 b
+  , Element arr3 (a, b)
+  ) =>
+  arr1 a ->
+  arr2 b ->
+  arr3 (a, b)
+zip = zipWith (,)
+{-# INLINE zip #-}
+
+{- | Replace all locations in the input with the same value.
+
+  Equivalent to Data.Functor.'Data.Functor.<$'.
+-}
+(<$) ::
+  ( Contiguous arr1
+  , Contiguous arr2
+  , Element arr1 b
+  , Element arr2 a
+  ) =>
+  a ->
+  arr1 b ->
+  arr2 a
+a <$ barr = create (replicateMut (size barr) a)
+{-# INLINE (<$) #-}
+
+{- | Sequential application.
+
+  Equivalent to Control.Applicative.'Control.Applicative.<*>'.
+-}
+ap ::
+  ( Contiguous arr1
+  , Contiguous arr2
+  , Contiguous arr3
+  , Element arr1 (a -> b)
+  , Element arr2 a
+  , Element arr3 b
+  ) =>
+  arr1 (a -> b) ->
+  arr2 a ->
+  arr3 b
+ap fs xs = create $ do
+  marr <- new (szfs * szxs)
+  let go1 !ix = when (ix < szfs) $ do
+        f <- indexM fs ix
+        go2 (ix * szxs) f 0
+        go1 (ix + 1)
+      go2 !off f !j = when (j < szxs) $ do
+        x <- indexM xs j
+        write marr (off + j) (f x)
+        go2 off f (j + 1)
+  go1 0
+  pure marr
+ where
+  !szfs = size fs
+  !szxs = size xs
+{-# INLINE ap #-}
+
+all :: (Contiguous arr, Element arr a) => (a -> Bool) -> arr a -> Bool
+all f = foldr (\x acc -> f x && acc) True
+{-# INLINE all #-}
+
+any :: (Contiguous arr, Element arr a) => (a -> Bool) -> arr a -> Bool
+any f = foldr (\x acc -> f x || acc) False
+{-# INLINE any #-}
diff --git a/src/Data/Primitive/Contiguous/Class.hs b/src/Data/Primitive/Contiguous/Class.hs
--- a/src/Data/Primitive/Contiguous/Class.hs
+++ b/src/Data/Primitive/Contiguous/Class.hs
@@ -14,39 +14,58 @@
 {-# LANGUAGE UnboxedTuples #-}
 {-# LANGUAGE UnliftedNewtypes #-}
 
--- | The 'Contiguous' typeclass parameterises over a contiguous array type.
--- It provides the core primitives necessary to implement the common API in "Data.Primitive.Contiguous".
---   This allows us to have a common API to a number of contiguous
---   array types and their mutable counterparts.
-
+{- | The 'Contiguous' typeclass parameterises over a contiguous array type.
+It provides the core primitives necessary to implement the common API in "Data.Primitive.Contiguous".
+  This allows us to have a common API to a number of contiguous
+  array types and their mutable counterparts.
+-}
 module Data.Primitive.Contiguous.Class
-  ( Contiguous(..)
-  , Slice(..)
-  , MutableSlice(..)
-  , ContiguousU(..)
+  ( Contiguous (..)
+  , Slice (..)
+  , MutableSlice (..)
+  , ContiguousU (..)
   , Always
   ) where
 
-
+import Data.Primitive hiding (fromList, fromListN)
 import Data.Primitive.Contiguous.Shim
-import Data.Primitive hiding (fromList,fromListN)
 import Data.Primitive.Unlifted.Array
-import Prelude hiding (length,map,all,any,foldr,foldMap,traverse,read,filter,replicate,null,reverse,foldl,foldr,zip,zipWith,scanl,(<$),elem,maximum,minimum,mapM,mapM_,sequence,sequence_)
-
+import Prelude hiding
+  ( all
+  , any
+  , elem
+  , filter
+  , foldMap
+  , foldl
+  , foldr
+  , length
+  , map
+  , mapM
+  , mapM_
+  , maximum
+  , minimum
+  , null
+  , read
+  , replicate
+  , reverse
+  , scanl
+  , sequence
+  , sequence_
+  , traverse
+  , zip
+  , zipWith
+  , (<$)
+  )
 
 import Control.DeepSeq (NFData)
-import Control.Monad.Primitive (PrimState, PrimMonad(..))
-import Control.Monad.ST (runST,ST)
-import Control.Monad.ST.Run (runPrimArrayST,runSmallArrayST,runUnliftedArrayST,runArrayST)
+import Control.Monad.Primitive (PrimMonad (..), PrimState)
+import Control.Monad.ST (ST, runST)
+import Control.Monad.ST.Run (runArrayST, runPrimArrayST, runSmallArrayST, runUnliftedArrayST)
 import Data.Kind (Type)
+import Data.Primitive.Unlifted.Array ()
+import Data.Primitive.Unlifted.Array.Primops (MutableUnliftedArray# (MutableUnliftedArray#), UnliftedArray# (UnliftedArray#))
 import Data.Primitive.Unlifted.Class (PrimUnlifted)
-import GHC.Exts (ArrayArray#,Constraint,sizeofByteArray#,sizeofArray#,sizeofArrayArray#)
-import GHC.Exts (SmallMutableArray#,MutableArray#,MutableArrayArray#)
-import GHC.Exts (SmallArray#,Array#)
-import GHC.Exts (TYPE)
-import Data.Primitive.Unlifted.Array (MutableUnliftedArray,UnliftedArray)
-import Data.Primitive.Unlifted.Array (MutableUnliftedArray_(MutableUnliftedArray),UnliftedArray_(UnliftedArray))
-import Data.Primitive.Unlifted.Array.Primops (MutableUnliftedArray#(MutableUnliftedArray#),UnliftedArray#(UnliftedArray#))
+import GHC.Exts (Array#, Constraint, MutableArray#, SmallArray#, SmallMutableArray#, TYPE, sizeofArray#, sizeofByteArray#)
 
 import qualified Control.DeepSeq as DS
 import qualified Data.Primitive.Unlifted.Class as Class
@@ -61,90 +80,114 @@
 type UnliftedRep = 'UnliftedRep
 #endif
 
+{- | Slices of immutable arrays: packages an offset and length with a backing array.
 
--- | Slices of immutable arrays: packages an offset and length with a backing array.
---
--- @since 0.6.0
+@since 0.6.0
+-}
 data Slice arr a = Slice
   { offset :: {-# UNPACK #-} !Int
   , length :: {-# UNPACK #-} !Int
   , base :: !(Unlifted arr a)
   }
 
--- | Slices of mutable arrays: packages an offset and length with a mutable backing array.
---
--- @since 0.6.0
+{- | Slices of mutable arrays: packages an offset and length with a mutable backing array.
+
+@since 0.6.0
+-}
 data MutableSlice arr s a = MutableSlice
   { offsetMut :: {-# UNPACK #-} !Int
   , lengthMut :: {-# UNPACK #-} !Int
   , baseMut :: !(UnliftedMut arr s a)
   }
 
--- | The 'Contiguous' typeclass as an interface to a multitude of
--- contiguous structures.
---
--- Some functions do not make sense on slices; for those, see 'ContiguousU'.
+{- | The 'Contiguous' typeclass as an interface to a multitude of
+contiguous structures.
+
+Some functions do not make sense on slices; for those, see 'ContiguousU'.
+-}
 class Contiguous (arr :: Type -> Type) where
   -- | The Mutable counterpart to the array.
-  type family Mutable arr = (r :: Type -> Type -> Type) | r -> arr
+  type Mutable arr = (r :: Type -> Type -> Type) | r -> arr
+
   -- | The constraint needed to store elements in the array.
-  type family Element arr :: Type -> Constraint
+  type Element arr :: Type -> Constraint
+
   -- | The slice type of this array.
   -- The slice of a raw array type @t@ should be 'Slice t',
   -- whereas the slice of a slice should be the same slice type.
   --
   -- @since 0.6.0
-  type family Sliced arr :: Type -> Type
+  type Sliced arr :: Type -> Type
+
   -- | The mutable slice type of this array.
   -- The mutable slice of a raw array type @t@ should be 'MutableSlice t',
   -- whereas the mutable slice of a mutable slice should be the same slice type.
   --
   -- @since 0.6.0
-  type family MutableSliced arr :: Type -> Type -> Type
-
+  type MutableSliced arr :: Type -> Type -> Type
 
   ------ Construction ------
+
   -- | Allocate a new mutable array of the given size.
   new :: (PrimMonad m, Element arr b) => Int -> m (Mutable arr (PrimState m) b)
+
   -- | @'replicateMut' n x@ is a mutable array of length @n@ with @x@ the
   -- value of every element.
-  replicateMut :: (PrimMonad m, Element arr b)
-    => Int -- length
-    -> b -- fill element
-    -> m (Mutable arr (PrimState m) b)
+  replicateMut ::
+    (PrimMonad m, Element arr b) =>
+    Int -> -- length
+    b -> -- fill element
+    m (Mutable arr (PrimState m) b)
+
   -- | Resize an array without growing it.
   --
   -- @since 0.6.0
-  shrink :: (PrimMonad m, Element arr a)
-    => Mutable arr (PrimState m) a
-    -> Int -- ^ new length
-    -> m (Mutable arr (PrimState m) a)
+  shrink ::
+    (PrimMonad m, Element arr a) =>
+    Mutable arr (PrimState m) a ->
+    -- | new length
+    Int ->
+    m (Mutable arr (PrimState m) a)
   default shrink ::
-       ( ContiguousU arr
-       , PrimMonad m, Element arr a)
-    => Mutable arr (PrimState m) a -> Int -> m (Mutable arr (PrimState m) a)
+    ( ContiguousU arr
+    , PrimMonad m
+    , Element arr a
+    ) =>
+    Mutable arr (PrimState m) a ->
+    Int ->
+    m (Mutable arr (PrimState m) a)
   {-# INLINE shrink #-}
   shrink = resize
+
   -- | The empty array.
   empty :: arr a
+
   -- | Create a singleton array.
-  singleton :: Element arr a => a -> arr a
+  singleton :: (Element arr a) => a -> arr a
+
   -- | Create a doubleton array.
-  doubleton :: Element arr a => a -> a -> arr a
+  doubleton :: (Element arr a) => a -> a -> arr a
+
   -- | Create a tripleton array.
-  tripleton :: Element arr a => a -> a -> a -> arr a
+  tripleton :: (Element arr a) => a -> a -> a -> arr a
+
   -- | Create a quadrupleton array.
-  quadrupleton :: Element arr a => a -> a -> a -> a -> arr a
+  quadrupleton :: (Element arr a) => a -> a -> a -> a -> arr a
+
   -- | Create a quintupleton array.
-  quintupleton :: Element arr a => a -> a -> a -> a -> a -> arr a
+  quintupleton :: (Element arr a) => a -> a -> a -> a -> a -> arr a
+
   -- | Create a sextupleton array.
-  sextupleton :: Element arr a => a -> a -> a -> a -> a -> a -> arr a
+  sextupleton :: (Element arr a) => a -> a -> a -> a -> a -> a -> arr a
 
   ------ Access and Update ------
+
   -- | Index into an array at the given index.
-  index :: Element arr b => arr b -> Int -> b
+  index :: (Element arr b) => arr b -> Int -> b
+
   -- | Index into an array at the given index, yielding an unboxed one-tuple of the element.
-  index# :: Element arr b => arr b -> Int -> (# b #)
+  index# :: (Element arr b) => arr b -> Int -> (# b #)
+
   -- | Indexing in a monad.
   --
   --   The monad allows operations to be strict in the array
@@ -165,211 +208,318 @@
   --   Here, no references to @v@ are retained because indexing
   --   (but /not/ the elements) is evaluated eagerly.
   indexM :: (Element arr b, Monad m) => arr b -> Int -> m b
+
   -- | Read a mutable array at the given index.
-  read :: (PrimMonad m, Element arr b)
-       => Mutable arr (PrimState m) b -> Int -> m b
+  read ::
+    (PrimMonad m, Element arr b) =>
+    Mutable arr (PrimState m) b ->
+    Int ->
+    m b
+
   -- | Write to a mutable array at the given index.
-  write :: (PrimMonad m, Element arr b)
-        => Mutable arr (PrimState m) b -> Int -> b -> m ()
+  write ::
+    (PrimMonad m, Element arr b) =>
+    Mutable arr (PrimState m) b ->
+    Int ->
+    b ->
+    m ()
 
   ------ Properties ------
+
   -- | Test whether the array is empty.
   null :: arr b -> Bool
+
   -- | The size of the array
-  size :: Element arr b => arr b -> Int
+  size :: (Element arr b) => arr b -> Int
+
   -- | The size of the mutable array
-  sizeMut :: (PrimMonad m, Element arr b)
-    => Mutable arr (PrimState m) b -> m Int
+  sizeMut ::
+    (PrimMonad m, Element arr b) =>
+    Mutable arr (PrimState m) b ->
+    m Int
+
   -- | Test the two arrays for equality.
   equals :: (Element arr b, Eq b) => arr b -> arr b -> Bool
+
   -- | Test the two mutable arrays for pointer equality.
   --   Does not check equality of elements.
   equalsMut :: Mutable arr s a -> Mutable arr s a -> Bool
 
   ------ Conversion ------
+
   -- | Create a 'Slice' of an array.
   --
   -- @O(1)@.
   --
   -- @since 0.6.0
-  slice :: (Element arr a)
-    => arr a -- base array
-    -> Int -- offset
-    -> Int -- length
-    -> Sliced arr a
+  slice ::
+    (Element arr a) =>
+    arr a -> -- base array
+    Int -> -- offset
+    Int -> -- length
+    Sliced arr a
+
   -- | Create a 'MutableSlice' of a mutable array.
   --
   -- @O(1)@.
   --
   -- @since 0.6.0
-  sliceMut :: (Element arr a)
-    => Mutable arr s a -- base array
-    -> Int -- offset
-    -> Int -- length
-    -> MutableSliced arr s a
+  sliceMut ::
+    (Element arr a) =>
+    Mutable arr s a -> -- base array
+    Int -> -- offset
+    Int -> -- length
+    MutableSliced arr s a
+
   -- | Create a 'Slice' that covers the entire array.
   --
   -- @since 0.6.0
   toSlice :: (Element arr a) => arr a -> Sliced arr a
+
   -- | Create a 'MutableSlice' that covers the entire array.
   --
   -- @since 0.6.0
-  toSliceMut :: (PrimMonad m, Element arr a)
-    => Mutable arr (PrimState m) a
-    -> m (MutableSliced arr (PrimState m) a)
+  toSliceMut ::
+    (PrimMonad m, Element arr a) =>
+    Mutable arr (PrimState m) a ->
+    m (MutableSliced arr (PrimState m) a)
+
   -- | Clone a slice of an array.
-  clone :: Element arr b
-    => Sliced arr b -- ^ slice to copy
-    -> arr b
+  clone ::
+    (Element arr b) =>
+    -- | slice to copy
+    Sliced arr b ->
+    arr b
   default clone ::
-       ( Sliced arr ~ Slice arr, ContiguousU arr
-       , Element arr b)
-    => Sliced arr b -> arr b
+    ( Sliced arr ~ Slice arr
+    , ContiguousU arr
+    , Element arr b
+    ) =>
+    Sliced arr b ->
+    arr b
   {-# INLINE clone #-}
-  clone Slice{offset,length,base} = clone_ (lift base) offset length
+  clone Slice {offset, length, base} = clone_ (lift base) offset length
+
   -- | Clone a slice of an array without using the 'Slice' type.
   -- These methods are required to implement 'Contiguous (Slice arr)' for any `Contiguous arr`;
   -- they are not really meant for direct use.
   --
   -- @since 0.6.0
-  clone_ :: Element arr a => arr a -> Int -> Int -> arr a
+  clone_ :: (Element arr a) => arr a -> Int -> Int -> arr a
+
   -- | Clone a slice of a mutable array.
-  cloneMut :: (PrimMonad m, Element arr b)
-    => MutableSliced arr (PrimState m) b -- ^ Array to copy a slice of
-    -> m (Mutable arr (PrimState m) b)
+  cloneMut ::
+    (PrimMonad m, Element arr b) =>
+    -- | Array to copy a slice of
+    MutableSliced arr (PrimState m) b ->
+    m (Mutable arr (PrimState m) b)
   default cloneMut ::
-       ( MutableSliced arr ~ MutableSlice arr, ContiguousU arr
-       , PrimMonad m, Element arr b)
-    => MutableSliced arr (PrimState m) b -> m (Mutable arr (PrimState m) b)
+    ( MutableSliced arr ~ MutableSlice arr
+    , ContiguousU arr
+    , PrimMonad m
+    , Element arr b
+    ) =>
+    MutableSliced arr (PrimState m) b ->
+    m (Mutable arr (PrimState m) b)
   {-# INLINE cloneMut #-}
-  cloneMut MutableSlice{offsetMut,lengthMut,baseMut}
-    = cloneMut_ (liftMut baseMut) offsetMut lengthMut
+  cloneMut MutableSlice {offsetMut, lengthMut, baseMut} =
+    cloneMut_ (liftMut baseMut) offsetMut lengthMut
+
   -- | Clone a slice of a mutable array without using the 'MutableSlice' type.
   -- These methods are required to implement 'Contiguous (Slice arr)' for any `Contiguous arr`;
   -- they are not really meant for direct use.
   --
   -- @since 0.6.0
-  cloneMut_ :: (PrimMonad m, Element arr b)
-    => Mutable arr (PrimState m) b -- ^ Array to copy a slice of
-    -> Int -- ^ offset
-    -> Int -- ^ length
-    -> m (Mutable arr (PrimState m) b)
+  cloneMut_ ::
+    (PrimMonad m, Element arr b) =>
+    -- | Array to copy a slice of
+    Mutable arr (PrimState m) b ->
+    -- | offset
+    Int ->
+    -- | length
+    Int ->
+    m (Mutable arr (PrimState m) b)
+
   -- | Turn a mutable array slice an immutable array by copying.
   --
   -- @since 0.6.0
-  freeze :: (PrimMonad m, Element arr a)
-    => MutableSliced arr (PrimState m) a
-    -> m (arr a)
+  freeze ::
+    (PrimMonad m, Element arr a) =>
+    MutableSliced arr (PrimState m) a ->
+    m (arr a)
   default freeze ::
-       ( MutableSliced arr ~ MutableSlice arr, ContiguousU arr
-       , PrimMonad m, Element arr a)
-    => MutableSliced arr (PrimState m) a -> m (arr a)
+    ( MutableSliced arr ~ MutableSlice arr
+    , ContiguousU arr
+    , PrimMonad m
+    , Element arr a
+    ) =>
+    MutableSliced arr (PrimState m) a ->
+    m (arr a)
   {-# INLINE freeze #-}
-  freeze MutableSlice{offsetMut,lengthMut,baseMut}
-    = freeze_ (liftMut baseMut) offsetMut lengthMut
+  freeze MutableSlice {offsetMut, lengthMut, baseMut} =
+    freeze_ (liftMut baseMut) offsetMut lengthMut
+
   -- | Turn a slice of a mutable array into an immutable one with copying,
   -- without using the 'MutableSlice' type.
   -- These methods are required to implement 'Contiguous (Slice arr)' for any `Contiguous arr`;
   -- they are not really meant for direct use.
   --
   -- @since 0.6.0
-  freeze_ :: (PrimMonad m, Element arr b)
-    => Mutable arr (PrimState m) b
-    -> Int -- ^ offset
-    -> Int -- ^ length
-    -> m (arr b)
+  freeze_ ::
+    (PrimMonad m, Element arr b) =>
+    Mutable arr (PrimState m) b ->
+    -- | offset
+    Int ->
+    -- | length
+    Int ->
+    m (arr b)
+
   -- | Turn a mutable array into an immutable one without copying.
   --   The mutable array should not be used after this conversion.
-  unsafeFreeze :: (PrimMonad m, Element arr b)
-    => Mutable arr (PrimState m) b
-    -> m (arr b)
+  unsafeFreeze ::
+    (PrimMonad m, Element arr b) =>
+    Mutable arr (PrimState m) b ->
+    m (arr b)
   unsafeFreeze xs = unsafeShrinkAndFreeze xs =<< sizeMut xs
   {-# INLINE unsafeFreeze #-}
-  unsafeShrinkAndFreeze :: (PrimMonad m, Element arr a)
-    => Mutable arr (PrimState m) a
-    -> Int -- ^ final size
-    -> m (arr a)
+
+  unsafeShrinkAndFreeze ::
+    (PrimMonad m, Element arr a) =>
+    Mutable arr (PrimState m) a ->
+    -- | final size
+    Int ->
+    m (arr a)
   default unsafeShrinkAndFreeze ::
-       ( ContiguousU arr
-       , PrimMonad m, Element arr a)
-    => Mutable arr (PrimState m) a -> Int -> m (arr a)
+    ( ContiguousU arr
+    , PrimMonad m
+    , Element arr a
+    ) =>
+    Mutable arr (PrimState m) a ->
+    Int ->
+    m (arr a)
   {-# INLINE unsafeShrinkAndFreeze #-}
   unsafeShrinkAndFreeze arr0 len' =
     resize arr0 len' >>= unsafeFreeze
+
   -- | Copy a slice of an immutable array into a new mutable array.
-  thaw :: (PrimMonad m, Element arr b)
-    => Sliced arr b
-    -> m (Mutable arr (PrimState m) b)
+  thaw ::
+    (PrimMonad m, Element arr b) =>
+    Sliced arr b ->
+    m (Mutable arr (PrimState m) b)
   default thaw ::
-       ( Sliced arr ~ Slice arr, ContiguousU arr
-       , PrimMonad m, Element arr b)
-    => Sliced arr b
-    -> m (Mutable arr (PrimState m) b)
+    ( Sliced arr ~ Slice arr
+    , ContiguousU arr
+    , PrimMonad m
+    , Element arr b
+    ) =>
+    Sliced arr b ->
+    m (Mutable arr (PrimState m) b)
   {-# INLINE thaw #-}
-  thaw Slice{offset,length,base} = thaw_ (lift base) offset length
+  thaw Slice {offset, length, base} = thaw_ (lift base) offset length
+
   -- | Copy a slice of an immutable array into a new mutable array without using the 'Slice' type.
   -- These methods are required to implement 'Contiguous (Slice arr)' for any `Contiguous arr`;
   -- they are not really meant for direct use.
   --
   -- @since 0.6.0
-  thaw_ :: (PrimMonad m, Element arr b)
-    => arr b
-    -> Int -- ^ offset into the array
-    -> Int -- ^ length of the slice
-    -> m (Mutable arr (PrimState m) b)
+  thaw_ ::
+    (PrimMonad m, Element arr b) =>
+    arr b ->
+    -- | offset into the array
+    Int ->
+    -- | length of the slice
+    Int ->
+    m (Mutable arr (PrimState m) b)
 
   ------ Copy Operations ------
+
   -- | Copy a slice of an array into a mutable array.
-  copy :: (PrimMonad m, Element arr b)
-    => Mutable arr (PrimState m) b -- ^ destination array
-    -> Int -- ^ offset into destination array
-    -> Sliced arr b -- ^ source slice
-    -> m ()
+  copy ::
+    (PrimMonad m, Element arr b) =>
+    -- | destination array
+    Mutable arr (PrimState m) b ->
+    -- | offset into destination array
+    Int ->
+    -- | source slice
+    Sliced arr b ->
+    m ()
   default copy ::
-      ( Sliced arr ~ Slice arr, ContiguousU arr
-      , PrimMonad m, Element arr b)
-    => Mutable arr (PrimState m) b -> Int -> Sliced arr b -> m ()
+    ( Sliced arr ~ Slice arr
+    , ContiguousU arr
+    , PrimMonad m
+    , Element arr b
+    ) =>
+    Mutable arr (PrimState m) b ->
+    Int ->
+    Sliced arr b ->
+    m ()
   {-# INLINE copy #-}
-  copy dst dstOff Slice{offset,length,base} = copy_ dst dstOff (lift base) offset length
+  copy dst dstOff Slice {offset, length, base} = copy_ dst dstOff (lift base) offset length
+
   -- | Copy a slice of an array into a mutable array without using the 'Slice' type.
   -- These methods are required to implement 'Contiguous (Slice arr)' for any `Contiguous arr`;
   -- they are not really meant for direct use.
   --
   -- @since 0.6.0
-  copy_ :: (PrimMonad m, Element arr b)
-    => Mutable arr (PrimState m) b -- ^ destination array
-    -> Int -- ^ offset into destination array
-    -> arr b -- ^ source array
-    -> Int -- ^ offset into source array
-    -> Int -- ^ number of elements to copy
-    -> m ()
+  copy_ ::
+    (PrimMonad m, Element arr b) =>
+    -- | destination array
+    Mutable arr (PrimState m) b ->
+    -- | offset into destination array
+    Int ->
+    -- | source array
+    arr b ->
+    -- | offset into source array
+    Int ->
+    -- | number of elements to copy
+    Int ->
+    m ()
+
   -- | Copy a slice of a mutable array into another mutable array.
   --   In the case that the destination and source arrays are the
   --   same, the regions may overlap.
-  copyMut :: (PrimMonad m, Element arr b)
-    => Mutable arr (PrimState m) b -- ^ destination array
-    -> Int -- ^ offset into destination array
-    -> MutableSliced arr (PrimState m) b -- ^ source slice
-    -> m ()
+  copyMut ::
+    (PrimMonad m, Element arr b) =>
+    -- | destination array
+    Mutable arr (PrimState m) b ->
+    -- | offset into destination array
+    Int ->
+    -- | source slice
+    MutableSliced arr (PrimState m) b ->
+    m ()
   default copyMut ::
-       ( MutableSliced arr ~ MutableSlice arr, ContiguousU arr
-       , PrimMonad m, Element arr b)
-    => Mutable arr (PrimState m) b -> Int -> MutableSliced arr (PrimState m) b -> m ()
+    ( MutableSliced arr ~ MutableSlice arr
+    , ContiguousU arr
+    , PrimMonad m
+    , Element arr b
+    ) =>
+    Mutable arr (PrimState m) b ->
+    Int ->
+    MutableSliced arr (PrimState m) b ->
+    m ()
   {-# INLINE copyMut #-}
-  copyMut dst dstOff MutableSlice{offsetMut,lengthMut,baseMut}
-    = copyMut_ dst dstOff (liftMut baseMut) offsetMut lengthMut
+  copyMut dst dstOff MutableSlice {offsetMut, lengthMut, baseMut} =
+    copyMut_ dst dstOff (liftMut baseMut) offsetMut lengthMut
+
   -- | Copy a slice of a mutable array into another mutable array without using the 'Slice' type.
   -- These methods are required to implement 'Contiguous (Slice arr)' for any `Contiguous arr`;
   -- they are not really meant for direct use.
   --
   -- @since 0.6.0
-  copyMut_ :: (PrimMonad m, Element arr b)
-    => Mutable arr (PrimState m) b -- ^ destination array
-    -> Int -- ^ offset into destination array
-    -> Mutable arr (PrimState m) b -- ^ source array
-    -> Int -- ^ offset into source array
-    -> Int -- ^ number of elements to copy
-    -> m ()
+  copyMut_ ::
+    (PrimMonad m, Element arr b) =>
+    -- | destination array
+    Mutable arr (PrimState m) b ->
+    -- | offset into destination array
+    Int ->
+    -- | source array
+    Mutable arr (PrimState m) b ->
+    -- | offset into source array
+    Int ->
+    -- | number of elements to copy
+    Int ->
+    m ()
+
   -- | Copy a slice of an array and then insert an element into that array.
   --
   -- The default implementation performs a memset which would be unnecessary
@@ -377,179 +527,204 @@
   --
   -- Was previously @insertSlicing@
   -- @since 0.6.0
-  insertAt :: (Element arr b)
-    => arr b -- ^ slice to copy from
-    -> Int -- ^ index in the output array to insert at
-    -> b -- ^ element to insert
-    -> arr b
+  insertAt ::
+    (Element arr b) =>
+    -- | slice to copy from
+    arr b ->
+    -- | index in the output array to insert at
+    Int ->
+    -- | element to insert
+    b ->
+    arr b
   default insertAt ::
-       (Element arr b, ContiguousU arr)
-    => arr b -> Int -> b -> arr b
+    (Element arr b, ContiguousU arr) =>
+    arr b ->
+    Int ->
+    b ->
+    arr b
   insertAt src i x = run $ do
     dst <- replicateMut (size src + 1) x
     copy dst 0 (slice src 0 i)
     copy dst (i + 1) (slice src i (size src - i))
     unsafeFreeze dst
-  {-# inline insertAt #-}
+  {-# INLINE insertAt #-}
 
   ------ Reduction ------
+
   -- | Reduce the array and all of its elements to WHNF.
   rnf :: (NFData a, Element arr a) => arr a -> ()
+
   -- | Run an effectful computation that produces an array.
   run :: (forall s. ST s (arr a)) -> arr a
 
--- | The 'ContiguousU' typeclass is an extension of the 'Contiguous' typeclass,
--- but includes operations that make sense only on unsliced contiguous structures.
---
--- @since 0.6.0
+{- | The 'ContiguousU' typeclass is an extension of the 'Contiguous' typeclass,
+but includes operations that make sense only on unsliced contiguous structures.
+
+@since 0.6.0
+-}
 class (Contiguous arr) => ContiguousU arr where
   -- | The unifted version of the immutable array type (i.e. eliminates an indirection through a thunk).
   type Unlifted arr = (r :: Type -> TYPE UnliftedRep) | r -> arr
+
   -- | The unifted version of the mutable array type (i.e. eliminates an indirection through a thunk).
   type UnliftedMut arr = (r :: Type -> Type -> TYPE UnliftedRep) | r -> arr
+
   -- | Resize an array into one with the given size.
-  resize :: (PrimMonad m, Element arr b)
-         => Mutable arr (PrimState m) b
-         -> Int
-         -> m (Mutable arr (PrimState m) b)
+  resize ::
+    (PrimMonad m, Element arr b) =>
+    Mutable arr (PrimState m) b ->
+    Int ->
+    m (Mutable arr (PrimState m) b)
+
   -- | Unlift an array (i.e. point to the data without an intervening thunk).
   --
   -- @since 0.6.0
   unlift :: arr b -> Unlifted arr b
+
   -- | Unlift a mutable array (i.e. point to the data without an intervening thunk).
   --
   -- @since 0.6.0
   unliftMut :: Mutable arr s b -> UnliftedMut arr s b
+
   -- | Lift an array (i.e. point to the data through an intervening thunk).
   --
   -- @since 0.6.0
   lift :: Unlifted arr b -> arr b
+
   -- | Lift a mutable array (i.e. point to the data through an intervening thunk).
   --
   -- @since 0.6.0
   liftMut :: UnliftedMut arr s b -> Mutable arr s b
 
+{- | A typeclass that is satisfied by all types. This is used
+used to provide a fake constraint for 'Array' and 'SmallArray'.
+-}
+class Always a
 
--- | A typeclass that is satisfied by all types. This is used
--- used to provide a fake constraint for 'Array' and 'SmallArray'.
-class Always a where {}
-instance Always a where {}
+instance Always a
 
 instance (ContiguousU arr) => Contiguous (Slice arr) where
   type Mutable (Slice arr) = MutableSlice arr
   type Element (Slice arr) = Element arr
   type Sliced (Slice arr) = Slice arr
   type MutableSliced (Slice arr) = MutableSlice arr
+
   ------ Construction ------
   {-# INLINE new #-}
   new len = do
     baseMut <- new len
-    pure MutableSlice{offsetMut=0,lengthMut=len,baseMut=unliftMut baseMut}
+    pure MutableSlice {offsetMut = 0, lengthMut = len, baseMut = unliftMut baseMut}
   {-# INLINE replicateMut #-}
   replicateMut len x = do
     baseMut <- replicateMut len x
-    pure MutableSlice{offsetMut=0,lengthMut=len,baseMut=unliftMut baseMut}
+    pure MutableSlice {offsetMut = 0, lengthMut = len, baseMut = unliftMut baseMut}
   {-# INLINE shrink #-}
   shrink xs len' = pure $ case compare len' (lengthMut xs) of
-    LT -> xs{lengthMut=len'}
+    LT -> xs {lengthMut = len'}
     EQ -> xs
     GT -> errorWithoutStackTrace "Data.Primitive.Contiguous.Class.shrink: passed a larger than existing size"
   {-# INLINE empty #-}
-  empty = Slice{offset=0,length=0,base=unlift empty}
+  empty = Slice {offset = 0, length = 0, base = unlift empty}
   {-# INLINE singleton #-}
-  singleton a = Slice{offset=0,length=1,base=unlift $ singleton a}
+  singleton a = Slice {offset = 0, length = 1, base = unlift $ singleton a}
   {-# INLINE doubleton #-}
-  doubleton a b = Slice{offset=0,length=2,base=unlift $ doubleton a b}
+  doubleton a b = Slice {offset = 0, length = 2, base = unlift $ doubleton a b}
   {-# INLINE tripleton #-}
-  tripleton a b c = Slice{offset=0,length=3,base=unlift $ tripleton a b c}
+  tripleton a b c = Slice {offset = 0, length = 3, base = unlift $ tripleton a b c}
   {-# INLINE quadrupleton #-}
-  quadrupleton a b c d = Slice{offset=0,length=4,base=unlift $ quadrupleton a b c d}
+  quadrupleton a b c d = Slice {offset = 0, length = 4, base = unlift $ quadrupleton a b c d}
   {-# INLINE quintupleton #-}
-  quintupleton a b c d e = Slice{offset=0,length=5,base=unlift $ quintupleton a b c d e}
+  quintupleton a b c d e = Slice {offset = 0, length = 5, base = unlift $ quintupleton a b c d e}
   {-# INLINE sextupleton #-}
-  sextupleton a b c d e f = Slice{offset=0,length=6,base=unlift $ sextupleton a b c d e f}
+  sextupleton a b c d e f = Slice {offset = 0, length = 6, base = unlift $ sextupleton a b c d e f}
 
   ------ Access and Update ------
   {-# INLINE index #-}
-  index Slice{offset,base} i = index (lift base) (offset + i)
+  index Slice {offset, base} i = index (lift base) (offset + i)
   {-# INLINE index# #-}
-  index# Slice{offset,base} i = index# (lift base) (offset + i)
+  index# Slice {offset, base} i = index# (lift base) (offset + i)
   {-# INLINE indexM #-}
-  indexM Slice{offset,base} i = indexM (lift base) (offset + i)
+  indexM Slice {offset, base} i = indexM (lift base) (offset + i)
   {-# INLINE read #-}
-  read MutableSlice{offsetMut,baseMut} i = read (liftMut baseMut) (offsetMut + i)
+  read MutableSlice {offsetMut, baseMut} i = read (liftMut baseMut) (offsetMut + i)
   {-# INLINE write #-}
-  write MutableSlice{offsetMut,baseMut} i = write (liftMut baseMut) (offsetMut + i)
+  write MutableSlice {offsetMut, baseMut} i = write (liftMut baseMut) (offsetMut + i)
 
   ------ Properties ------
   {-# INLINE null #-}
-  null Slice{length} = length == 0
+  null Slice {length} = length == 0
   {-# INLINE size #-}
-  size Slice{length} = length
+  size Slice {length} = length
   {-# INLINE sizeMut #-}
-  sizeMut MutableSlice{lengthMut} = pure lengthMut
+  sizeMut MutableSlice {lengthMut} = pure lengthMut
   {-# INLINE equals #-}
-  equals Slice{offset=oA,length=lenA,base=a}
-         Slice{offset=oB,length=lenB,base=b}
-    = lenA == lenB && loop 0 oA oB
-    where
-    loop !i !iA !iB =
-      if i == lenA then True
-      else index (lift a) iA == index (lift b) iB && loop (i+1) (iA+1) (iB+1)
+  equals
+    Slice {offset = oA, length = lenA, base = a}
+    Slice {offset = oB, length = lenB, base = b} =
+      lenA == lenB && loop 0 oA oB
+     where
+      loop !i !iA !iB =
+        if i == lenA
+          then True
+          else index (lift a) iA == index (lift b) iB && loop (i + 1) (iA + 1) (iB + 1)
   {-# INLINE equalsMut #-}
-  equalsMut MutableSlice{offsetMut=offA,lengthMut=lenA,baseMut=a}
-                MutableSlice{offsetMut=offB,lengthMut=lenB,baseMut=b}
-    =  liftMut a `equalsMut` liftMut b
-    && offA == offB
-    && lenA == lenB
+  equalsMut
+    MutableSlice {offsetMut = offA, lengthMut = lenA, baseMut = a}
+    MutableSlice {offsetMut = offB, lengthMut = lenB, baseMut = b} =
+      liftMut a `equalsMut` liftMut b
+        && offA == offB
+        && lenA == lenB
 
   ------ Conversion ------
   {-# INLINE slice #-}
-  slice Slice{offset,base} off' len' = Slice
-    { offset = offset + off'
-    , length = len'
-    , base
-    }
+  slice Slice {offset, base} off' len' =
+    Slice
+      { offset = offset + off'
+      , length = len'
+      , base
+      }
   {-# INLINE sliceMut #-}
-  sliceMut MutableSlice{offsetMut,baseMut} off' len' = MutableSlice
-    { offsetMut = offsetMut + off'
-    , lengthMut = len'
-    , baseMut
-    }
+  sliceMut MutableSlice {offsetMut, baseMut} off' len' =
+    MutableSlice
+      { offsetMut = offsetMut + off'
+      , lengthMut = len'
+      , baseMut
+      }
   {-# INLINE clone #-}
   clone = id
   {-# INLINE clone_ #-}
-  clone_ Slice{offset,base} off' len' =
-    Slice{offset=offset+off',length=len',base}
+  clone_ Slice {offset, base} off' len' =
+    Slice {offset = offset + off', length = len', base}
   {-# INLINE cloneMut #-}
-  cloneMut xs@MutableSlice{lengthMut} = cloneMut_ xs 0 lengthMut
+  cloneMut xs@MutableSlice {lengthMut} = cloneMut_ xs 0 lengthMut
   {-# INLINE cloneMut_ #-}
-  cloneMut_ MutableSlice{offsetMut,baseMut} off' len' = do
+  cloneMut_ MutableSlice {offsetMut, baseMut} off' len' = do
     baseMut' <- cloneMut_ (liftMut baseMut) (offsetMut + off') len'
-    pure MutableSlice{offsetMut=0,lengthMut=len',baseMut=unliftMut baseMut'}
+    pure MutableSlice {offsetMut = 0, lengthMut = len', baseMut = unliftMut baseMut'}
   {-# INLINE freeze #-}
-  freeze xs@MutableSlice{lengthMut}
-    = freeze_ xs 0 lengthMut
+  freeze xs@MutableSlice {lengthMut} =
+    freeze_ xs 0 lengthMut
   {-# INLINE freeze_ #-}
-  freeze_ MutableSlice{offsetMut,baseMut} off' len' = do
+  freeze_ MutableSlice {offsetMut, baseMut} off' len' = do
     base <- freeze_ (liftMut baseMut) (offsetMut + off') len'
-    pure Slice{offset=0,length=len',base=unlift base}
+    pure Slice {offset = 0, length = len', base = unlift base}
   {-# INLINE unsafeShrinkAndFreeze #-}
-  unsafeShrinkAndFreeze MutableSlice{offsetMut=0,lengthMut,baseMut} len' = do
-    shrunk <- if lengthMut /= len'
-      then resize (liftMut baseMut) len'
-      else pure (liftMut baseMut)
+  unsafeShrinkAndFreeze MutableSlice {offsetMut = 0, lengthMut, baseMut} len' = do
+    shrunk <-
+      if lengthMut /= len'
+        then resize (liftMut baseMut) len'
+        else pure (liftMut baseMut)
     base <- unsafeFreeze shrunk
-    pure Slice{offset=0,length=len',base=unlift base}
-  unsafeShrinkAndFreeze MutableSlice{offsetMut,baseMut} len' = do
+    pure Slice {offset = 0, length = len', base = unlift base}
+  unsafeShrinkAndFreeze MutableSlice {offsetMut, baseMut} len' = do
     base <- freeze_ (liftMut baseMut) offsetMut len'
-    pure Slice{offset=0,length=len',base=unlift base}
+    pure Slice {offset = 0, length = len', base = unlift base}
   {-# INLINE thaw #-}
-  thaw xs@Slice{length} = thaw_ xs 0 length
+  thaw xs@Slice {length} = thaw_ xs 0 length
   {-# INLINE thaw_ #-}
-  thaw_ Slice{offset,base} off' len' = do
+  thaw_ Slice {offset, base} off' len' = do
     baseMut <- thaw_ (lift base) (offset + off') len'
-    pure MutableSlice{offsetMut=0,lengthMut=len',baseMut=unliftMut baseMut}
+    pure MutableSlice {offsetMut = 0, lengthMut = len', baseMut = unliftMut baseMut}
   {-# INLINE toSlice #-}
   toSlice = id
   {-# INLINE toSliceMut #-}
@@ -557,37 +732,41 @@
 
   ------ Copy Operations ------
   {-# INLINE copy #-}
-  copy dst dstOff src@Slice{length} = copy_ dst dstOff src 0 length
+  copy dst dstOff src@Slice {length} = copy_ dst dstOff src 0 length
   {-# INLINE copy_ #-}
-  copy_ MutableSlice{offsetMut,baseMut} dstOff Slice{offset,base} off' len =
+  copy_ MutableSlice {offsetMut, baseMut} dstOff Slice {offset, base} off' len =
     copy_ (liftMut baseMut) (offsetMut + dstOff) (lift base) (offset + off') len
   {-# INLINE copyMut #-}
-  copyMut dst dstOff src@MutableSlice{lengthMut} = copyMut_ dst dstOff src 0 lengthMut
+  copyMut dst dstOff src@MutableSlice {lengthMut} = copyMut_ dst dstOff src 0 lengthMut
   {-# INLINE copyMut_ #-}
-  copyMut_ MutableSlice{offsetMut=dstOff,baseMut=dst} dstOff'
-           MutableSlice{offsetMut=srcOff,baseMut=src} srcOff' len =
-    copyMut_ (liftMut dst) (dstOff + dstOff') (liftMut src) (srcOff + srcOff') len
+  copyMut_
+    MutableSlice {offsetMut = dstOff, baseMut = dst}
+    dstOff'
+    MutableSlice {offsetMut = srcOff, baseMut = src}
+    srcOff'
+    len =
+      copyMut_ (liftMut dst) (dstOff + dstOff') (liftMut src) (srcOff + srcOff') len
   {-# INLINE insertAt #-}
-  insertAt Slice{offset,length,base} i x = run $ do
+  insertAt Slice {offset, length, base} i x = run $ do
     dst <- replicateMut (length + 1) x
     copy_ dst 0 (lift base) offset i
     copy_ dst (i + 1) (lift base) (offset + i) (length - i)
     base' <- unsafeFreeze dst
-    pure Slice{offset=0,length=length+1,base=unlift base'}
+    pure Slice {offset = 0, length = length + 1, base = unlift base'}
 
   ------ Reduction ------
   {-# INLINE rnf #-}
-  rnf !arr@Slice{length} =
-    let go !ix = if ix < length
-          then
-            let !(# x #) = index# arr ix
-             in DS.rnf x `seq` go (ix + 1)
-          else ()
+  rnf !arr@Slice {length} =
+    let go !ix =
+          if ix < length
+            then
+              let !(# x #) = index# arr ix
+               in DS.rnf x `seq` go (ix + 1)
+            else ()
      in go 0
   {-# INLINE run #-}
   run = runST
 
-
 instance Contiguous SmallArray where
   type Mutable SmallArray = SmallMutableArray
   type Element SmallArray = Always
@@ -612,15 +791,15 @@
     0 -> True
     _ -> False
   {-# INLINE slice #-}
-  slice base offset length = Slice{offset,length,base=unlift base}
+  slice base offset length = Slice {offset, length, base = unlift base}
   {-# INLINE sliceMut #-}
-  sliceMut baseMut offsetMut lengthMut = MutableSlice{offsetMut,lengthMut,baseMut=unliftMut baseMut}
+  sliceMut baseMut offsetMut lengthMut = MutableSlice {offsetMut, lengthMut, baseMut = unliftMut baseMut}
   {-# INLINE toSlice #-}
-  toSlice base = Slice{offset=0,length=size base,base=unlift base}
+  toSlice base = Slice {offset = 0, length = size base, base = unlift base}
   {-# INLINE toSliceMut #-}
   toSliceMut baseMut = do
     lengthMut <- sizeMut baseMut
-    pure MutableSlice{offsetMut=0,lengthMut,baseMut=unliftMut baseMut}
+    pure MutableSlice {offsetMut = 0, lengthMut, baseMut = unliftMut baseMut}
   {-# INLINE freeze_ #-}
   freeze_ = freezeSmallArray
   {-# INLINE unsafeFreeze #-}
@@ -677,11 +856,12 @@
   {-# INLINE rnf #-}
   rnf !ary =
     let !sz = sizeofSmallArray ary
-        go !ix = if ix < sz
-          then
-            let !(# x #) = indexSmallArray## ary ix
-             in DS.rnf x `seq` go (ix + 1)
-          else ()
+        go !ix =
+          if ix < sz
+            then
+              let !(# x #) = indexSmallArray## ary ix
+               in DS.rnf x `seq` go (ix + 1)
+            else ()
      in go 0
   {-# INLINE clone_ #-}
   clone_ = cloneSmallArray
@@ -710,7 +890,6 @@
   {-# INLINE liftMut #-}
   liftMut x = SmallMutableArray x
 
-
 instance Contiguous PrimArray where
   type Mutable PrimArray = MutablePrimArray
   type Element PrimArray = Prim
@@ -737,15 +916,15 @@
   {-# INLINE sizeMut #-}
   sizeMut = getSizeofMutablePrimArray
   {-# INLINE slice #-}
-  slice base offset length = Slice{offset,length,base=unlift base}
+  slice base offset length = Slice {offset, length, base = unlift base}
   {-# INLINE sliceMut #-}
-  sliceMut baseMut offsetMut lengthMut = MutableSlice{offsetMut,lengthMut,baseMut=unliftMut baseMut}
+  sliceMut baseMut offsetMut lengthMut = MutableSlice {offsetMut, lengthMut, baseMut = unliftMut baseMut}
   {-# INLINE toSlice #-}
-  toSlice base = Slice{offset=0,length=size base,base=unlift base}
+  toSlice base = Slice {offset = 0, length = size base, base = unlift base}
   {-# INLINE toSliceMut #-}
   toSliceMut baseMut = do
     lengthMut <- sizeMut baseMut
-    pure MutableSlice{offsetMut=0,lengthMut,baseMut=unliftMut baseMut}
+    pure MutableSlice {offsetMut = 0, lengthMut, baseMut = unliftMut baseMut}
   {-# INLINE freeze_ #-}
   freeze_ = freezePrimArrayShim
   {-# INLINE unsafeFreeze #-}
@@ -841,7 +1020,6 @@
   {-# INLINE liftMut #-}
   liftMut (MutablePrimArray# x) = MutablePrimArray x
 
-
 instance Contiguous Array where
   type Mutable Array = MutableArray
   type Element Array = Always
@@ -868,15 +1046,15 @@
   {-# INLINE sizeMut #-}
   sizeMut = (\x -> pure $! sizeofMutableArray x)
   {-# INLINE slice #-}
-  slice base offset length = Slice{offset,length,base=unlift base}
+  slice base offset length = Slice {offset, length, base = unlift base}
   {-# INLINE sliceMut #-}
-  sliceMut baseMut offsetMut lengthMut = MutableSlice{offsetMut,lengthMut,baseMut=unliftMut baseMut}
+  sliceMut baseMut offsetMut lengthMut = MutableSlice {offsetMut, lengthMut, baseMut = unliftMut baseMut}
   {-# INLINE toSlice #-}
-  toSlice base = Slice{offset=0,length=size base,base=unlift base}
+  toSlice base = Slice {offset = 0, length = size base, base = unlift base}
   {-# INLINE toSliceMut #-}
   toSliceMut baseMut = do
     lengthMut <- sizeMut baseMut
-    pure MutableSlice{offsetMut=0,lengthMut,baseMut=unliftMut baseMut}
+    pure MutableSlice {offsetMut = 0, lengthMut, baseMut = unliftMut baseMut}
   {-# INLINE freeze_ #-}
   freeze_ = freezeArray
   {-# INLINE unsafeFreeze #-}
@@ -888,7 +1066,7 @@
   {-# INLINE copyMut_ #-}
   copyMut_ = copyMutableArray
   {-# INLINE clone #-}
-  clone Slice{offset,length,base} = clone_ (lift base) offset length
+  clone Slice {offset, length, base} = clone_ (lift base) offset length
   {-# INLINE clone_ #-}
   clone_ = cloneArray
   {-# INLINE cloneMut_ #-}
@@ -908,7 +1086,7 @@
           | i == sz = ()
           | otherwise =
               let !(# x #) = indexArray## ary i
-               in DS.rnf x `seq` go (i+1)
+               in DS.rnf x `seq` go (i + 1)
      in go 0
   {-# INLINE singleton #-}
   singleton a = runArrayST (newArray 1 a >>= unsafeFreezeArray)
@@ -964,7 +1142,7 @@
   {-# INLINE liftMut #-}
   liftMut x = MutableArray x
 
-class (Class.Unlifted a ~ u, PrimUnlifted a) => PrimUnliftsInto (u :: TYPE ('Exts.BoxedRep 'Exts.Unlifted)) (a :: Type) where
+class (Class.Unlifted a ~ u, PrimUnlifted a) => PrimUnliftsInto (u :: TYPE ('Exts.BoxedRep 'Exts.Unlifted)) (a :: Type)
 instance (Class.Unlifted a ~ u, PrimUnlifted a) => PrimUnliftsInto u a
 
 instance Contiguous (UnliftedArray_ unlifted_a) where
@@ -993,19 +1171,19 @@
   {-# INLINE sizeMut #-}
   sizeMut = pure . sizeofMutableUnliftedArray
   {-# INLINE slice #-}
-  slice base offset length = Slice{offset,length,base=unlift base}
+  slice base offset length = Slice {offset, length, base = unlift base}
   {-# INLINE sliceMut #-}
-  sliceMut baseMut offsetMut lengthMut = MutableSlice{offsetMut,lengthMut,baseMut=unliftMut baseMut}
+  sliceMut baseMut offsetMut lengthMut = MutableSlice {offsetMut, lengthMut, baseMut = unliftMut baseMut}
   {-# INLINE freeze_ #-}
   freeze_ = freezeUnliftedArray
   {-# INLINE unsafeFreeze #-}
   unsafeFreeze = unsafeFreezeUnliftedArray
   {-# INLINE toSlice #-}
-  toSlice base = Slice{offset=0,length=size base,base=unlift base}
+  toSlice base = Slice {offset = 0, length = size base, base = unlift base}
   {-# INLINE toSliceMut #-}
   toSliceMut baseMut = do
     lengthMut <- sizeMut baseMut
-    pure MutableSlice{offsetMut=0,lengthMut,baseMut=unliftMut baseMut}
+    pure MutableSlice {offsetMut = 0, lengthMut, baseMut = unliftMut baseMut}
   {-# INLINE thaw_ #-}
   thaw_ = thawUnliftedArray
   {-# INLINE copy_ #-}
@@ -1031,7 +1209,7 @@
           | i == sz = ()
           | otherwise =
               let x = indexUnliftedArray ary i
-               in DS.rnf x `seq` go (i+1)
+               in DS.rnf x `seq` go (i + 1)
      in go 0
   {-# INLINE singleton #-}
   singleton a = runUnliftedArrayST (newUnliftedArray 1 a >>= unsafeFreezeUnliftedArray)
@@ -1073,10 +1251,10 @@
   {-# INLINE run #-}
   run = runUnliftedArrayST
 
-newtype UnliftedArray## (u :: TYPE UnliftedRep) (a :: Type) =
-  UnliftedArray## (Exts.Array# u)
-newtype MutableUnliftedArray## (u :: TYPE UnliftedRep) s (a :: Type) =
-  MutableUnliftedArray## (Exts.MutableArray# s u)
+newtype UnliftedArray## (u :: TYPE UnliftedRep) (a :: Type)
+  = UnliftedArray## (Exts.Array# u)
+newtype MutableUnliftedArray## (u :: TYPE UnliftedRep) s (a :: Type)
+  = MutableUnliftedArray## (Exts.MutableArray# s u)
 
 instance ContiguousU (UnliftedArray_ unlifted_a) where
   type Unlifted (UnliftedArray_ unlifted_a) = UnliftedArray## unlifted_a
diff --git a/src/Data/Primitive/Contiguous/Shim.hs b/src/Data/Primitive/Contiguous/Shim.hs
--- a/src/Data/Primitive/Contiguous/Shim.hs
+++ b/src/Data/Primitive/Contiguous/Shim.hs
@@ -15,36 +15,36 @@
 
 import Control.Monad (when)
 import Control.Monad.ST.Run (runPrimArrayST)
-import Data.Primitive hiding (fromList,fromListN)
+import Data.Primitive hiding (fromList, fromListN)
 import Data.Primitive.Unlifted.Array
-import Prelude hiding (map,all,any,foldr,foldMap,traverse,read,filter,replicate,null,reverse,foldl,foldr,zip,zipWith,scanl,(<$),elem,maximum,minimum,mapM,mapM_,sequence,sequence_)
+import Prelude hiding (all, any, elem, filter, foldMap, foldl, foldr, map, mapM, mapM_, maximum, minimum, null, read, replicate, reverse, scanl, sequence, sequence_, traverse, zip, zipWith, (<$))
 
+import Control.Monad.Primitive (PrimMonad (..), PrimState)
 import Data.Primitive.Unlifted.Class (PrimUnlifted)
-import Control.Monad.Primitive (PrimState, PrimMonad(..))
 
-
 errorThunk :: a
 errorThunk = error "Contiguous typeclass: unitialized element"
-{-# noinline errorThunk #-}
+{-# NOINLINE errorThunk #-}
 
-resizeArray :: PrimMonad m => MutableArray (PrimState m) a -> Int -> m (MutableArray (PrimState m) a)
+resizeArray :: (PrimMonad m) => MutableArray (PrimState m) a -> Int -> m (MutableArray (PrimState m) a)
 resizeArray !src !sz = do
   dst <- newArray sz errorThunk
   copyMutableArray dst 0 src 0 (min sz (sizeofMutableArray src))
   pure dst
-{-# inline resizeArray #-}
+{-# INLINE resizeArray #-}
 
-resizeSmallArray :: PrimMonad m => SmallMutableArray (PrimState m) a -> Int -> m (SmallMutableArray (PrimState m) a)
+resizeSmallArray :: (PrimMonad m) => SmallMutableArray (PrimState m) a -> Int -> m (SmallMutableArray (PrimState m) a)
 resizeSmallArray !src !sz = do
   dst <- newSmallArray sz errorThunk
   copySmallMutableArray dst 0 src 0 (min sz (sizeofSmallMutableArray src))
   pure dst
-{-# inline resizeSmallArray #-}
+{-# INLINE resizeSmallArray #-}
 
-replicateSmallMutableArray :: (PrimMonad m)
-  => Int
-  -> a
-  -> m (SmallMutableArray (PrimState m) a)
+replicateSmallMutableArray ::
+  (PrimMonad m) =>
+  Int ->
+  a ->
+  m (SmallMutableArray (PrimState m) a)
 replicateSmallMutableArray len a = do
   marr <- newSmallArray len errorThunk
   let go !ix = when (ix < len) $ do
@@ -52,42 +52,45 @@
         go (ix + 1)
   go 0
   pure marr
-{-# inline replicateSmallMutableArray #-}
+{-# INLINE replicateSmallMutableArray #-}
 
 resizeUnliftedArray :: (PrimMonad m, PrimUnlifted a) => MutableUnliftedArray (PrimState m) a -> Int -> m (MutableUnliftedArray (PrimState m) a)
 resizeUnliftedArray !src !sz = do
   dst <- unsafeNewUnliftedArray sz
   copyMutableUnliftedArray dst 0 src 0 (min sz (sizeofMutableUnliftedArray src))
   pure dst
-{-# inline resizeUnliftedArray #-}
+{-# INLINE resizeUnliftedArray #-}
 
-replicateMutablePrimArray :: (PrimMonad m, Prim a)
-  => Int -- ^ length
-  -> a -- ^ element
-  -> m (MutablePrimArray (PrimState m) a)
+replicateMutablePrimArray ::
+  (PrimMonad m, Prim a) =>
+  -- | length
+  Int ->
+  -- | element
+  a ->
+  m (MutablePrimArray (PrimState m) a)
 replicateMutablePrimArray len a = do
   marr <- newPrimArray len
   setPrimArray marr 0 len a
   pure marr
-{-# inline replicateMutablePrimArray #-}
+{-# INLINE replicateMutablePrimArray #-}
 
-clonePrimArrayShim :: Prim a => PrimArray a -> Int -> Int -> PrimArray a
+clonePrimArrayShim :: (Prim a) => PrimArray a -> Int -> Int -> PrimArray a
 clonePrimArrayShim !arr !off !len = runPrimArrayST $ do
   marr <- newPrimArray len
   copyPrimArray marr 0 arr off len
   unsafeFreezePrimArray marr
-{-# inline clonePrimArrayShim #-}
+{-# INLINE clonePrimArrayShim #-}
 
 cloneMutablePrimArrayShim :: (PrimMonad m, Prim a) => MutablePrimArray (PrimState m) a -> Int -> Int -> m (MutablePrimArray (PrimState m) a)
 cloneMutablePrimArrayShim !arr !off !len = do
   marr <- newPrimArray len
   copyMutablePrimArray marr 0 arr off len
   pure marr
-{-# inline cloneMutablePrimArrayShim #-}
+{-# INLINE cloneMutablePrimArrayShim #-}
 
 freezePrimArrayShim :: (PrimMonad m, Prim a) => MutablePrimArray (PrimState m) a -> Int -> Int -> m (PrimArray a)
 freezePrimArrayShim !src !off !len = do
   dst <- newPrimArray len
   copyMutablePrimArray dst 0 src off len
   unsafeFreezePrimArray dst
-{-# inline freezePrimArrayShim #-}
+{-# INLINE freezePrimArrayShim #-}
diff --git a/test/Laws.hs b/test/Laws.hs
--- a/test/Laws.hs
+++ b/test/Laws.hs
@@ -1,4 +1,6 @@
-{-# language InstanceSigs, TypeFamilies, UndecidableInstances #-}
+{-# LANGUAGE InstanceSigs #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE UndecidableInstances #-}
 
 -- We define a newtype around `Array a` for the purpose of testing
 -- the definitions of many typeclass methods from `Data.Primitive.Contiguous`.
@@ -8,30 +10,33 @@
 
 import Data.Foldable
 import Data.Primitive.Contiguous
+import qualified Data.Primitive.Contiguous as C
 import Data.Proxy
+import qualified GHC.Exts as Exts
 import Test.QuickCheck
 import Test.QuickCheck.Classes
-import qualified Data.Primitive.Contiguous as C
-import qualified GHC.Exts as Exts
 
 main :: IO ()
 main = lawsCheckMany laws
 
 laws :: [(String, [Laws])]
 laws =
-  [ ("Arr", [ functorLaws arr
-            , applicativeLaws arr
-            , foldableLaws arr
-            , traversableLaws arr
-            , isListLaws arr1
-            ]
+  [
+    ( "Arr"
+    ,
+      [ functorLaws arr
+      , applicativeLaws arr
+      , foldableLaws arr
+      , traversableLaws arr
+      , isListLaws arr1
+      ]
     )
   ]
 
 newtype Arr a = Arr (Array a)
   deriving (Eq, Show)
 
-instance Arbitrary a => Arbitrary (Arr a) where
+instance (Arbitrary a) => Arbitrary (Arr a) where
   arbitrary = fmap (Arr . Exts.fromList) arbitrary
 
 arr :: Proxy Arr
@@ -59,10 +64,10 @@
   length (Arr a) = C.size a
 
 instance Traversable Arr where
-  traverse :: Applicative f => (a -> f b) -> Arr a -> f (Arr b)
+  traverse :: (Applicative f) => (a -> f b) -> Arr a -> f (Arr b)
   traverse f (Arr a) = fmap Arr (C.traverse f a)
 
-  sequenceA :: Applicative f => Arr (f a) -> f (Arr a)
+  sequenceA :: (Applicative f) => Arr (f a) -> f (Arr a)
   sequenceA (Arr f) = fmap Arr (C.sequence f)
 
 instance Exts.IsList (Arr a) where
@@ -70,5 +75,3 @@
   fromList = Arr . C.fromList
   fromListN len = Arr . C.fromListN len
   toList (Arr a) = Exts.toList a
-
-
diff --git a/test/UnitTests.hs b/test/UnitTests.hs
--- a/test/UnitTests.hs
+++ b/test/UnitTests.hs
@@ -1,59 +1,60 @@
-{-# language ExistentialQuantification #-}
-{-# language GeneralizedNewtypeDeriving #-}
-{-# language ScopedTypeVariables #-}
-{-# language UndecidableInstances #-}
+{-# LANGUAGE ExistentialQuantification #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE UndecidableInstances #-}
 
 module Main (main) where
 
-import Data.Functor.Identity (Identity(..))
+import qualified Data.Either as P
+import Data.Functor.Identity (Identity (..))
+import qualified Data.List as P
+import qualified Data.Maybe as P
 import Data.Monoid
 import Data.Primitive
-import Prelude
-import Test.QuickCheck
-import Test.QuickCheck.Instances ()
-import qualified Data.Maybe as P
 import qualified Data.Primitive.Contiguous as C
+import qualified Data.Vector as V
 import qualified GHC.Exts as Exts
+import Test.QuickCheck
+import Test.QuickCheck.Instances ()
+import Prelude
 import qualified Prelude as P
-import qualified Data.Either as P
-import qualified Data.List as P
-import qualified Data.Vector as V
 
 main :: IO ()
 main = unitTests
 
 unitTests :: IO ()
-unitTests = mapM_ testC
-  [ quiet "Contiguous.filter = Data.List.filter" prop_filter
-  , quiet "Contiguous.mapMaybe = Data.Maybe.mapMaybe" prop_mapMaybe
-  , quiet "Reverse: reverse . reverse = id" prop_reverse1
-  , quiet "Contiguous.reverse = Data.List.reverse" prop_reverse2
-  , quiet "Contiguous.map = Data.List.map" prop_map
-  , quiet "Contiguous.unfoldr = Data.List.unfoldr" prop_unfoldr
-  , quiet "Contiguous.unfoldrN = Data.Vector.unfoldrN" prop_unfoldrN
-  , quiet "Contiguous.traverse = Data.Traversable.traverse" prop_traverse
-  , quiet "Contiguous.find = Data.Foldable.find" prop_find
-  , quiet "Contiguous.scanl = Data.List.scanl" prop_scanl
-  , quiet "Contiguous.scanl' = Data.List.scanl'" prop_scanl'
-  , quiet "Contiguous.prescanl = Data.Vector.prescanl" prop_prescanl
-  , quiet "Contiguous.prescanl' = Data.Vector.prescanl'" prop_prescanl'
-  , quiet "Contiguous.generate = Data.Vector.generate" prop_generate
-  , quiet "Contiguous.generateM = Data.Vector.generateM" prop_generateM
-  , quiet "Contiguous.minimum = Data.Foldable.minimum" prop_minimum
-  , quiet "Contiguous.maximum = Data.Foldable.maximum" prop_maximum
-  , quiet "Contiguous.zipWith = Data.List.zipWith" prop_zipWith
-  , quiet "Contiguous.zip = Data.List.zip" prop_zip
-  , quiet "Contiguous.lefts = Data.Either.lefts" prop_lefts
-  , quiet "Contiguous.rights = Data.Either.rights" prop_rights
-  , quiet "Contiguous.partitionEithers = Data.Either.partitionEithers" prop_partitionEithers
-  ]
+unitTests =
+  mapM_
+    testC
+    [ quiet "Contiguous.filter = Data.List.filter" prop_filter
+    , quiet "Contiguous.mapMaybe = Data.Maybe.mapMaybe" prop_mapMaybe
+    , quiet "Reverse: reverse . reverse = id" prop_reverse1
+    , quiet "Contiguous.reverse = Data.List.reverse" prop_reverse2
+    , quiet "Contiguous.map = Data.List.map" prop_map
+    , quiet "Contiguous.unfoldr = Data.List.unfoldr" prop_unfoldr
+    , quiet "Contiguous.unfoldrN = Data.Vector.unfoldrN" prop_unfoldrN
+    , quiet "Contiguous.traverse = Data.Traversable.traverse" prop_traverse
+    , quiet "Contiguous.find = Data.Foldable.find" prop_find
+    , quiet "Contiguous.scanl = Data.List.scanl" prop_scanl
+    , quiet "Contiguous.scanl' = Data.List.scanl'" prop_scanl'
+    , quiet "Contiguous.prescanl = Data.Vector.prescanl" prop_prescanl
+    , quiet "Contiguous.prescanl' = Data.Vector.prescanl'" prop_prescanl'
+    , quiet "Contiguous.generate = Data.Vector.generate" prop_generate
+    , quiet "Contiguous.generateM = Data.Vector.generateM" prop_generateM
+    , quiet "Contiguous.minimum = Data.Foldable.minimum" prop_minimum
+    , quiet "Contiguous.maximum = Data.Foldable.maximum" prop_maximum
+    , quiet "Contiguous.zipWith = Data.List.zipWith" prop_zipWith
+    , quiet "Contiguous.zip = Data.List.zip" prop_zip
+    , quiet "Contiguous.lefts = Data.Either.lefts" prop_lefts
+    , quiet "Contiguous.rights = Data.Either.rights" prop_rights
+    , quiet "Contiguous.partitionEithers = Data.Either.partitionEithers" prop_partitionEithers
+    ]
 
 -- Verbosity with which to run tests.
 data Verbosity = Quiet | Verbose
 
 -- | Hide the prop type.
-data Prop = forall prop. Testable prop => Prop prop
-
+data Prop = forall prop. (Testable prop) => Prop prop
 
 -- hack to let us get away with stuffing different
 -- prop types in a list
@@ -64,12 +65,12 @@
   }
 
 -- quiet output of a test
-quiet :: Testable prop => String -> prop -> CTest
+quiet :: (Testable prop) => String -> prop -> CTest
 quiet l p = CTest Quiet l (Prop p)
 
 -- verbose output of a test
 -- Useful for failing tests
-_verbose :: Testable prop => String -> prop -> CTest
+_verbose :: (Testable prop) => String -> prop -> CTest
 _verbose l p = CTest Verbose l (Prop p)
 
 testC :: CTest -> IO ()
@@ -78,88 +79,98 @@
   putStrLn $ "-- " ++ lbl ++ " --"
   putStrLn $ P.replicate (length lbl + 6) '-'
   putStr "\n"
-  ($ p) $ case v of { Verbose -> verboseCheck; Quiet -> quickCheck }
+  ($ p) $ case v of Verbose -> verboseCheck; Quiet -> quickCheck
   putStr "\n"
 
 newtype Arr = Arr (Array L)
-  deriving (Eq,Show)
+  deriving (Eq, Show)
 
 newtype L = L [Int]
-  deriving (Eq,Ord,Exts.IsList)
+  deriving (Eq, Ord, Exts.IsList)
 
 instance Show L where
   show (L x) = show x
 
 instance Arbitrary L where
   arbitrary = do
-    j <- choose (1,6)
+    j <- choose (1, 6)
     fmap L $ vectorOf j arbitrary
 
 instance Arbitrary Arr where
   arbitrary = do
-    k <- choose (2,20)
+    k <- choose (2, 20)
     fmap (Arr . Exts.fromList) $ vectorOf k arbitrary
   shrink (Arr xs) = fmap Arr (fmap Exts.fromList $ shrink $ Exts.toList xs)
 
 mean :: forall t a. (Foldable t, Integral a) => t a -> a
 mean xs =
-  let (sum_ :: Sum a,len_ :: Sum a) = foldMap (\x -> (Sum x, Sum 1)) xs
-  in (round :: Double -> a) $ (fromIntegral (getSum sum_) / fromIntegral (getSum len_))
+  let (sum_ :: Sum a, len_ :: Sum a) = foldMap (\x -> (Sum x, Sum 1)) xs
+   in (round :: Double -> a) $ (fromIntegral (getSum sum_) / fromIntegral (getSum len_))
 
 prop_filter :: Arr -> Property
-prop_filter (Arr arr) = property $
-  let arrList = C.toList arr
-      p = \(L xs) -> all even xs
-   in P.filter p arrList == C.toList (C.filter p arr)
+prop_filter (Arr arr) =
+  property $
+    let arrList = C.toList arr
+        p = \(L xs) -> all even xs
+     in P.filter p arrList == C.toList (C.filter p arr)
 
 prop_mapMaybe :: Arr -> Property
-prop_mapMaybe (Arr arr) = property $
-  let arrList = C.toList arr
-      p = \(L xs) -> if all even xs then Just () else Nothing
-   in P.mapMaybe p arrList == C.toList (C.mapMaybe p arr :: Array ())
+prop_mapMaybe (Arr arr) =
+  property $
+    let arrList = C.toList arr
+        p = \(L xs) -> if all even xs then Just () else Nothing
+     in P.mapMaybe p arrList == C.toList (C.mapMaybe p arr :: Array ())
 
 prop_reverse1 :: Arr -> Property
-prop_reverse1 (Arr arr) = property $
-  C.reverse (C.reverse arr) == arr
+prop_reverse1 (Arr arr) =
+  property $
+    C.reverse (C.reverse arr) == arr
 
 prop_reverse2 :: Arr -> Property
-prop_reverse2 (Arr arr) = property $
-  let arrList = C.toList arr
-   in P.reverse arrList == C.toList (C.reverse arr)
+prop_reverse2 (Arr arr) =
+  property $
+    let arrList = C.toList arr
+     in P.reverse arrList == C.toList (C.reverse arr)
 
 prop_map :: Arr -> Property
-prop_map (Arr arr) = property $
-  let arrList = C.toList arr
-      f = \(L xs) -> mean xs
-   in P.map f arrList == C.toList (C.map f arr :: Array Int)
+prop_map (Arr arr) =
+  property $
+    let arrList = C.toList arr
+        f = \(L xs) -> mean xs
+     in P.map f arrList == C.toList (C.map f arr :: Array Int)
 
 prop_unfoldr :: Property
-prop_unfoldr = property $
-  let f = \n -> if n == 0 then Nothing else Just (n,n-1)
-      sz = 10
-   in P.unfoldr f sz == C.toList (C.unfoldr f sz :: Array Int)
+prop_unfoldr =
+  property $
+    let f = \n -> if n == 0 then Nothing else Just (n, n - 1)
+        sz = 10
+     in P.unfoldr f sz == C.toList (C.unfoldr f sz :: Array Int)
 
 prop_unfoldrN :: Property
-prop_unfoldrN = property $
-  let f = \n -> if n == 0 then Nothing else Just (n,n-1)
-      sz = 100
-   in V.toList (V.unfoldrN sz f 10) == C.toList (C.unfoldrN sz f 10 :: Array Int)
+prop_unfoldrN =
+  property $
+    let f = \n -> if n == 0 then Nothing else Just (n, n - 1)
+        sz = 100
+     in V.toList (V.unfoldrN sz f 10) == C.toList (C.unfoldrN sz f 10 :: Array Int)
 
 prop_traverse :: Arr -> Property
-prop_traverse (Arr arr) = property $
-  let arrList = C.toList arr
-      f = \(L xs) -> Identity (sum xs)
-   in runIdentity (P.traverse f arrList) == C.toList (runIdentity (C.traverse f arr :: Identity (Array Int)))
+prop_traverse (Arr arr) =
+  property $
+    let arrList = C.toList arr
+        f = \(L xs) -> Identity (sum xs)
+     in runIdentity (P.traverse f arrList) == C.toList (runIdentity (C.traverse f arr :: Identity (Array Int)))
 
 prop_generate :: Property
-prop_generate = property $
-  let f = \i -> if even i then Just i else Nothing
-  in V.toList (V.generate 20 f) == C.toList (C.generate 20 f :: Array (Maybe Int))
+prop_generate =
+  property $
+    let f = \i -> if even i then Just i else Nothing
+     in V.toList (V.generate 20 f) == C.toList (C.generate 20 f :: Array (Maybe Int))
 
 prop_generateM :: Property
-prop_generateM = property $
-  let f = \i -> if even i then Just i else Nothing
-  in fmap V.toList (V.generateM 20 f) == fmap C.toList (C.generateM 20 f :: Maybe (Array Int))
+prop_generateM =
+  property $
+    let f = \i -> if even i then Just i else Nothing
+     in fmap V.toList (V.generateM 20 f) == fmap C.toList (C.generateM 20 f :: Maybe (Array Int))
 
 {-
 prop_postscanl :: Arr -> Property
@@ -170,90 +181,100 @@
 -}
 
 prop_prescanl :: Arr -> Property
-prop_prescanl (Arr arr) = property $
-  let arrList = V.fromList (C.toList arr)
-      f = \b (L a) -> b ++ a
-  in V.toList (V.prescanl f [] arrList) == C.toList (C.prescanl f [] arr :: Array [Int])
+prop_prescanl (Arr arr) =
+  property $
+    let arrList = V.fromList (C.toList arr)
+        f = \b (L a) -> b ++ a
+     in V.toList (V.prescanl f [] arrList) == C.toList (C.prescanl f [] arr :: Array [Int])
 
 prop_prescanl' :: Arr -> Property
-prop_prescanl' (Arr arr) = property $
-  let arrList = V.fromList (C.toList arr)
-      f = \b (L a) -> b ++ a
-  in V.toList (V.prescanl' f [] arrList) == C.toList (C.prescanl' f [] arr :: Array [Int])
+prop_prescanl' (Arr arr) =
+  property $
+    let arrList = V.fromList (C.toList arr)
+        f = \b (L a) -> b ++ a
+     in V.toList (V.prescanl' f [] arrList) == C.toList (C.prescanl' f [] arr :: Array [Int])
 
 prop_find :: Arr -> Property
-prop_find (Arr arr) = property $
-  let arrList = C.toList arr
-      f = \(L xs) -> even (sum xs)
-   in P.find f arrList == C.find f arr
+prop_find (Arr arr) =
+  property $
+    let arrList = C.toList arr
+        f = \(L xs) -> even (sum xs)
+     in P.find f arrList == C.find f arr
 
 prop_zipWith :: Arr -> Arr -> Property
-prop_zipWith (Arr arr1) (Arr arr2) = property $
-  let arrList1 = C.toList arr1
-      arrList2 = C.toList arr2
-      f = \(L xs) (L ys) -> xs ++ ys
-  in P.zipWith f arrList1 arrList2 == C.toList (C.zipWith f arr1 arr2 :: Array [Int])
+prop_zipWith (Arr arr1) (Arr arr2) =
+  property $
+    let arrList1 = C.toList arr1
+        arrList2 = C.toList arr2
+        f = \(L xs) (L ys) -> xs ++ ys
+     in P.zipWith f arrList1 arrList2 == C.toList (C.zipWith f arr1 arr2 :: Array [Int])
 
 prop_zip :: Arr -> Arr -> Property
-prop_zip (Arr arr1) (Arr arr2) = property $
-  let arrList1 = C.toList arr1
-      arrList2 = C.toList arr2
-  in P.zip arrList1 arrList2 == C.toList (C.zip arr1 arr2 :: Array (L, L))
+prop_zip (Arr arr1) (Arr arr2) =
+  property $
+    let arrList1 = C.toList arr1
+        arrList2 = C.toList arr2
+     in P.zip arrList1 arrList2 == C.toList (C.zip arr1 arr2 :: Array (L, L))
 prop_scanl :: Arr -> Property
-prop_scanl (Arr arr) = property $
-  let arrList = C.toList arr
-      f = \b (L a) -> b ++ a
-  in P.scanl f [] arrList == C.toList (C.scanl f [] arr :: Array [Int])
+prop_scanl (Arr arr) =
+  property $
+    let arrList = C.toList arr
+        f = \b (L a) -> b ++ a
+     in P.scanl f [] arrList == C.toList (C.scanl f [] arr :: Array [Int])
 
 prop_scanl' :: Arr -> Property
-prop_scanl' (Arr arr) = property $
-  let arrList = C.toList arr
-      f = \b (L a) -> b ++ a
-  in P.scanl' f [] arrList == C.toList (C.scanl' f [] arr :: Array [Int])
+prop_scanl' (Arr arr) =
+  property $
+    let arrList = C.toList arr
+        f = \b (L a) -> b ++ a
+     in P.scanl' f [] arrList == C.toList (C.scanl' f [] arr :: Array [Int])
 
 prop_partitionEithers :: Array' (Either Int Bool) -> Property
-prop_partitionEithers (Array' arr) = property $
-  let arrList = C.toList arr
-      rhs = case C.partitionEithers arr of (as,bs) -> (C.toList as, C.toList bs)
-  in P.partitionEithers arrList == rhs
+prop_partitionEithers (Array' arr) =
+  property $
+    let arrList = C.toList arr
+        rhs = case C.partitionEithers arr of (as, bs) -> (C.toList as, C.toList bs)
+     in P.partitionEithers arrList == rhs
 
 prop_rights :: Array' (Either Int Bool) -> Property
-prop_rights (Array' arr) = property $
-  let arrList = C.toList arr
-  in P.rights arrList == C.toList (C.rights arr)
+prop_rights (Array' arr) =
+  property $
+    let arrList = C.toList arr
+     in P.rights arrList == C.toList (C.rights arr)
 
 prop_lefts :: Array' (Either Int Bool) -> Property
-prop_lefts (Array' arr) = property $
-  let arrList = C.toList arr
-  in P.lefts arrList == C.toList (C.lefts arr)
+prop_lefts (Array' arr) =
+  property $
+    let arrList = C.toList arr
+     in P.lefts arrList == C.toList (C.lefts arr)
 
 prop_minimum :: Arr -> Property
-prop_minimum (Arr arr) = property $
-  let arrList = C.toList arr
-  in Just (minimum arrList) == C.minimum arr
+prop_minimum (Arr arr) =
+  property $
+    let arrList = C.toList arr
+     in Just (minimum arrList) == C.minimum arr
 
 prop_maximum :: Arr -> Property
-prop_maximum (Arr arr) = property $
-  let arrList = C.toList arr
-  in Just (maximum arrList) == C.maximum arr
+prop_maximum (Arr arr) =
+  property $
+    let arrList = C.toList arr
+     in Just (maximum arrList) == C.maximum arr
 
-newtype Array' a = Array' { getArray' :: Array a }
+newtype Array' a = Array' {getArray' :: Array a}
   deriving (Eq, Show, Exts.IsList)
 
-instance Arbitrary a => Arbitrary (Array' a) where
+instance (Arbitrary a) => Arbitrary (Array' a) where
   arbitrary = do
-    k <- choose (2,20)
+    k <- choose (2, 20)
     fmap Exts.fromList $ vectorOf k arbitrary
   shrink xs = fmap Exts.fromList $ shrink $ Exts.toList xs
 
 -- Get around quickcheck not generating multiple arrays
---newtype GenArrM = GenArr { getGenArrM :: Array Int }
+-- newtype GenArrM = GenArr { getGenArrM :: Array Int }
 --  deriving (Eq, Show, Exts.IsList)
 
---instance Arbitrary GenArrM where
+-- instance Arbitrary GenArrM where
 --  arbitrary = do
 --    k <- choose (2,20)
 --    GenArrM <$> C.generateM k (const arbitrary)
 --  shrink xs = fmap Exts.fromList $ shrink $ Exts.toList xs
-
-
