diff --git a/Data/Array/Dynamic/F.hs b/Data/Array/Dynamic/F.hs
new file mode 100644
--- /dev/null
+++ b/Data/Array/Dynamic/F.hs
@@ -0,0 +1,240 @@
+
+{-# language
+   RankNTypes, LambdaCase, KindSignatures, RoleAnnotations, BangPatterns,
+   GeneralizedNewtypeDeriving, UndecidableInstances #-}
+
+{-|
+Arrays of unboxed (flat) elements.
+-}
+
+module Data.Array.Dynamic.F  (
+    empty
+  , Array(..)
+  , capacity
+  , clear
+  , push
+  , pop
+  , Data.Array.Dynamic.F.read
+  , Data.Array.Dynamic.F.show
+  , size
+  , unsafeRead
+  , unsafeWrite
+  , write
+  , unsafeLast
+  , Data.Array.Dynamic.F.last
+  , isEmpty
+  , Data.Array.Dynamic.F.foldl'
+  , foldlIx'
+  , foldr'
+  , foldrIx'
+  , fromList
+  , freeze
+  , for
+  , forIx
+  ) where
+
+import Data.Unlifted
+import Data.Internal.Errors
+import Data.Kind
+
+import Data.Flat (Flat)
+
+import qualified Data.Ref.UU   as RUU
+import qualified Data.Ref.F    as RF
+import qualified Data.Array.FM as FM
+import qualified Data.Array.FI as FI
+
+type role Array representational
+newtype Array (a :: Type) = Array (RUU.Ref (RF.Ref Int) (FM.Array a))
+  deriving Unlifted
+
+defaultCapacity :: Int
+defaultCapacity = 5
+{-# inline defaultCapacity #-}
+
+empty :: forall a. Flat a => IO (Array a)
+empty = do
+  sizeRef <- RF.new 0
+  arrRef  <- FM.new defaultCapacity
+  Array <$> RUU.new sizeRef arrRef
+{-# inline empty #-}
+
+capacity :: Flat a => Array a -> IO Int
+capacity (Array r) = do
+  elems <- RUU.readSnd r
+  pure $! FM.size elems
+{-# inline capacity #-}
+
+unsafeRead :: Flat a => Array a -> Int -> IO a
+unsafeRead (Array r) i = do
+  elems <- RUU.readSnd r
+  FM.read elems i
+{-# inline unsafeRead #-}
+
+read :: Flat a => Array a -> Int -> IO a
+read (Array r) i = do
+  elems <- RUU.readSnd r
+  sizeRef <- RUU.readFst r
+  size <- RF.read sizeRef
+  if 0 <= i && i < size then
+    FM.read elems i
+  else
+    error "Data.Array.Dynamic.U.read: out of bounds"
+{-# inline read #-}
+
+unsafeWrite :: Flat a => Array a -> Int -> a -> IO ()
+unsafeWrite (Array r) i a = do
+  elems <- RUU.readSnd r
+  FM.write elems i a
+{-# inline unsafeWrite #-}
+
+write :: Flat a => Array a -> Int -> a -> IO ()
+write (Array r) i ~a = do
+  s <- RF.read =<< RUU.readFst r
+  if 0 <= i && i < s
+    then unsafeWrite (Array r) i a
+    else error "Data.Array.Dynamic.U.write: out of bounds"
+{-# inline write #-}
+
+push :: Flat a => Array a -> a -> IO ()
+push (Array r) ~a = do
+  sizeRef <- RUU.readFst r
+  elems   <- RUU.readSnd r
+  size    <- RF.read sizeRef
+  let cap = FM.size elems
+  RF.write sizeRef (size + 1)
+  if (size == cap) then do
+    let cap' = 2 * cap
+    elems' <- FM.new cap'
+    FM.copySlice elems 0 elems' 0 size
+    FM.write elems' size a
+    RUU.writeSnd r elems'
+  else do
+    FM.write elems size a
+{-# inline push #-}
+
+pop :: Flat a => Array a -> IO (Maybe a)
+pop (Array r) = do
+  sizeRef <- RUU.readFst r
+  size    <- RF.read sizeRef
+  case size of
+    0    -> pure Nothing
+    size -> do
+      elems <- RUU.readSnd r
+      let size' = size - 1
+      a <- FM.read elems size'
+      FM.write elems size' undefElem
+      RF.write sizeRef size'
+      pure $! Just a
+{-# inline pop #-}
+
+fromList :: Flat a => [a] -> IO (Array a)
+fromList as = do
+  let size = length as
+      cap  = size + defaultCapacity
+  sizeRef <- RF.new size
+  arrRef  <- FM.new cap
+  arr     <- RUU.new sizeRef arrRef
+  let go !i []     = pure ()
+      go i  (a:as) = FM.write arrRef i a >> go (i + 1) as
+  go 0 as
+  pure (Array arr)
+
+freeze :: Flat a => Array a -> IO (FI.Array a)
+freeze (Array arr) = do
+  sizeRef <- RUU.readFst arr
+  elems   <- RUU.readSnd arr
+  size    <- RF.read sizeRef
+  tgt     <- FM.new size
+  FM.copySlice elems 0 tgt 0 size
+  FM.unsafeFreeze tgt
+
+clear :: Flat a => Array a -> IO ()
+clear (Array r) = do
+  (`RF.write` 0) =<< RUU.readFst r
+  RUU.writeSnd r =<< FM.new defaultCapacity
+{-# inline clear #-}
+
+size :: Array a -> IO Int
+size (Array r) = RF.read =<< RUU.readFst r
+{-# inline size #-}
+
+unsafeLast :: Flat a => Array a -> IO a
+unsafeLast arr = do
+  i <- size arr
+  Data.Array.Dynamic.F.unsafeRead arr (i - 1)
+{-# inline unsafeLast #-}
+
+isEmpty :: Array a -> IO Bool
+isEmpty arr = (==0) <$> size arr
+{-# inline isEmpty #-}
+
+last :: Flat a => Array a -> IO a
+last arr = do
+  i <- size arr
+  isEmpty arr >>= \case
+    True -> error "Data.Array.Dynamic.U.last: empty array"
+    _    -> unsafeRead arr (i - 1)
+{-# inline last #-}
+
+show :: (Show a, Flat a) => Array a -> IO String
+show (Array r) = do
+  elems  <- RUU.readSnd r
+  size <- RF.read =<< RUU.readFst r
+  elems' <- FM.freezeSlice elems 0 size
+  pure (Prelude.show elems')
+{-# inlinable show #-}
+
+foldl' :: Flat a => (b -> a -> b) -> b -> Array a -> IO b
+foldl' f b = \arr -> do
+  s <- size arr
+  let go i b | i == s    = pure b
+             | otherwise = do
+                 a <- unsafeRead arr i
+                 go (i + 1) $! f b a
+  go 0 b
+{-# inline foldl' #-}
+
+foldlIx' :: Flat a => (Int -> b -> a -> b) -> b -> Array a -> IO b
+foldlIx' f b = \arr -> do
+  s <- size arr
+  let go i b | i == s    = pure b
+             | otherwise = do
+                 a <- unsafeRead arr i
+                 go (i + 1) $! f i b a
+  go 0 b
+{-# inline foldlIx' #-}
+
+foldr' :: Flat a => (a -> b -> b) -> b -> Array a -> IO b
+foldr' f b = \arr -> do
+  s <- size arr
+  let go i b | i == (-1) = pure b
+             | otherwise = do
+                 a <- unsafeRead arr i
+                 go (i - 1) $! f a b
+  go (s - 1) b
+{-# inline foldr' #-}
+
+foldrIx' :: Flat a => (Int -> a -> b -> b) -> b -> Array a -> IO b
+foldrIx' f b = \arr -> do
+  s <- size arr
+  let go i b | i == (-1) = pure b
+             | otherwise = do
+                 a <- unsafeRead arr i
+                 go (i - 1) $! f i a b
+  go (s - 1) b
+{-# inline foldrIx' #-}
+
+for :: Flat a => Array a -> (a -> IO b) -> IO ()
+for arr f = go (0 :: Int) where
+  go i = do
+    s <- size arr
+    if i == s then pure () else do {x <- unsafeRead arr i; f x; go (i + 1)}
+{-# inline for #-}
+
+forIx :: Flat a => Array a -> (Int -> a -> IO b) -> IO ()
+forIx arr f = go (0 :: Int) where
+  go i = do
+    s <- size arr
+    if i == s then pure () else do {x <- unsafeRead arr i; f i x; go (i + 1)}
+{-# inline forIx #-}
diff --git a/Data/Array/Dynamic/L.hs b/Data/Array/Dynamic/L.hs
new file mode 100644
--- /dev/null
+++ b/Data/Array/Dynamic/L.hs
@@ -0,0 +1,253 @@
+{-# language
+   RankNTypes, LambdaCase, KindSignatures, RoleAnnotations, BangPatterns,
+   GeneralizedNewtypeDeriving, UndecidableInstances #-}
+
+{-|
+Arrays of lifted elements.
+-}
+
+module Data.Array.Dynamic.L  (
+    empty
+  , Array(..)
+  , capacity
+  , clear
+  , push
+  , pop
+  , Data.Array.Dynamic.L.read
+  , Data.Array.Dynamic.L.show
+  , size
+  , unsafeRead
+  , unsafeWrite
+  , write
+  , modify'
+  , unsafeLast
+  , Data.Array.Dynamic.L.last
+  , isEmpty
+  , Data.Array.Dynamic.L.foldl'
+  , foldlIx'
+  , foldr'
+  , foldrIx'
+  , fromList
+  , freeze
+  , for
+  , forIx
+  ) where
+
+import Data.Unlifted
+import Data.Internal.Errors
+import Data.Kind
+
+import qualified Data.Ref.UU   as RUU
+import qualified Data.Ref.F    as RF
+import qualified Data.Array.LM as LM
+import qualified Data.Array.LI as LI
+
+type role Array representational
+newtype Array (a :: Type) = Array (RUU.Ref (RF.Ref Int) (LM.Array a))
+  deriving Unlifted
+
+defaultCapacity :: Int
+defaultCapacity = 5
+{-# inline defaultCapacity #-}
+
+fromList :: [a] -> IO (Array a)
+fromList as = do
+  let size = length as
+      cap  = size + defaultCapacity
+  sizeRef <- RF.new size
+  arrRef  <- LM.new cap undefElem
+  arr     <- RUU.new sizeRef arrRef
+  let go !i []     = pure ()
+      go i  (a:as) = LM.write arrRef i a >> go (i + 1) as
+  go 0 as
+  pure (Array arr)
+
+freeze :: Array a -> IO (LI.Array a)
+freeze (Array arr) = do
+  sizeRef <- RUU.readFst arr
+  elems   <- RUU.readSnd arr
+  size    <- RF.read sizeRef
+  tgt     <- LM.new size undefElem
+  LM.copySlice elems 0 tgt 0 size
+  LM.unsafeFreeze tgt
+
+empty :: forall a. IO (Array a)
+empty = do
+  sizeRef <- RF.new 0
+  arrRef  <- LM.new defaultCapacity undefElem
+  Array <$> RUU.new sizeRef arrRef
+{-# inline empty #-}
+
+capacity :: Array a -> IO Int
+capacity (Array r) = do
+  elems <- RUU.readSnd r
+  pure $! LM.size elems
+{-# inline capacity #-}
+
+unsafeRead :: Array a -> Int -> IO a
+unsafeRead (Array r) i = do
+  elems <- RUU.readSnd r
+  LM.read elems i
+{-# inline unsafeRead #-}
+
+read :: Array a -> Int -> IO a
+read (Array r) i = do
+  elems <- RUU.readSnd r
+  sizeRef <- RUU.readFst r
+  size <- RF.read sizeRef
+  if 0 <= i && i < size then
+    LM.read elems i
+  else
+    error "Data.Array.Dynamic.L.read: out of bounds"
+{-# inline read #-}
+
+unsafeWrite :: Array a -> Int -> a -> IO ()
+unsafeWrite (Array r) i a = do
+  elems <- RUU.readSnd r
+  LM.write elems i a
+{-# inline unsafeWrite #-}
+
+write :: Array a -> Int -> a -> IO ()
+write (Array r) i ~a = do
+  s <- RF.read =<< RUU.readFst r
+  if 0 <= i && i < s then
+    unsafeWrite (Array r) i a
+  else
+    error "Data.Array.Dynamic.L.write: out of bounds"
+{-# inline write #-}
+
+modify' :: Array a -> Int -> (a -> a) -> IO ()
+modify' (Array r) i f = do
+  s <- RF.read =<< RUU.readFst r
+  if 0 <= i && i < s then do
+    elems <- RUU.readSnd r
+    LM.modify' elems i f
+  else
+    error "Data.Array.Dynamic.L.write: out of bounds"
+{-# inline modify' #-}
+
+extendCapacity :: RUU.Ref (RF.Ref Int) (LM.Array a) -> a -> Int -> LM.Array a -> IO ()
+extendCapacity r ~a cap elems = do
+  let cap' = 2 * cap
+  elems' <- LM.new cap' undefElem
+  LM.copySlice elems 0 elems' 0 cap
+  LM.write elems' cap a
+  RUU.writeSnd r elems'
+{-# inlinable extendCapacity #-}
+
+push :: Array a -> a -> IO ()
+push (Array r) ~a = do
+  sizeRef <- RUU.readFst r
+  elems   <- RUU.readSnd r
+  size    <- RF.read sizeRef
+  let cap = LM.size elems
+  RF.write sizeRef (size + 1)
+  if (size == cap) then do
+    extendCapacity r a cap elems
+  else do
+    LM.write elems size a
+{-# inline push #-}
+
+pop :: Array a -> IO (Maybe a)
+pop (Array r) = do
+  sizeRef <- RUU.readFst r
+  size    <- RF.read sizeRef
+  case size of
+    0    -> pure Nothing
+    size -> do
+      elems <- RUU.readSnd r
+      let size' = size - 1
+      a <- LM.read elems size'
+      LM.write elems size' undefElem
+      RF.write sizeRef size'
+      pure $! Just a
+{-# inline pop #-}
+
+clear :: Array a -> IO ()
+clear (Array r) = do
+  (`RF.write` 0) =<< RUU.readFst r
+  RUU.writeSnd r =<< LM.new defaultCapacity undefElem
+{-# inline clear #-}
+
+size :: Array a -> IO Int
+size (Array r) = RF.read =<< RUU.readFst r
+{-# inline size #-}
+
+unsafeLast :: Array a -> IO a
+unsafeLast arr = do
+  i <- size arr
+  Data.Array.Dynamic.L.unsafeRead arr (i - 1)
+{-# inline unsafeLast #-}
+
+isEmpty :: Array a -> IO Bool
+isEmpty arr = (==0) <$> size arr
+{-# inline isEmpty #-}
+
+last :: Array a -> IO a
+last arr = do
+  i <- size arr
+  isEmpty arr >>= \case
+    True -> error "Data.Array.Dynamic.L.last: empty array"
+    _    -> unsafeRead arr (i - 1)
+{-# inline last #-}
+
+show :: Show a => Array a -> IO String
+show (Array r) = do
+  elems  <- RUU.readSnd r
+  size <- RF.read =<< RUU.readFst r
+  elems' <- LM.freezeSlice elems 0 size
+  pure (Prelude.show elems')
+
+foldl' :: forall a b. (b -> a -> b) -> b -> Array a -> IO b
+foldl' f b = \arr -> do
+  s <- size arr
+  let go i b | i == s    = pure b
+             | otherwise = do
+                 a <- unsafeRead arr i
+                 go (i + 1) $! f b a
+  go 0 b
+{-# inline foldl' #-}
+
+foldlIx' :: (Int -> b -> a -> b) -> b -> Array a -> IO b
+foldlIx' f b = \arr -> do
+  s <- size arr
+  let go i b | i == s    = pure b
+             | otherwise = do
+                 a <- unsafeRead arr i
+                 go (i + 1) $! f i b a
+  go 0 b
+{-# inline foldlIx' #-}
+
+foldr' :: (a -> b -> b) -> b -> Array a -> IO b
+foldr' f b = \arr -> do
+  s <- size arr
+  let go i b | i == (-1) = pure b
+             | otherwise = do
+                 a <- unsafeRead arr i
+                 go (i - 1) $! f a b
+  go (s - 1) b
+{-# inline foldr' #-}
+
+foldrIx' :: (Int -> a -> b -> b) -> b -> Array a -> IO b
+foldrIx' f b = \arr -> do
+  s <- size arr
+  let go i b | i == (-1) = pure b
+             | otherwise = do
+                 a <- unsafeRead arr i
+                 go (i - 1) $! f i a b
+  go (s - 1) b
+{-# inline foldrIx' #-}
+
+for :: Array a -> (a -> IO b) -> IO ()
+for arr f = go (0 :: Int) where
+  go i = do
+    s <- size arr
+    if i == s then pure () else do {x <- unsafeRead arr i; f x; go (i + 1)}
+{-# inline for #-}
+
+forIx :: Array a -> (Int -> a -> IO b) -> IO ()
+forIx arr f = go (0 :: Int) where
+  go i = do
+    s <- size arr
+    if i == s then pure () else do {x <- unsafeRead arr i; f i x; go (i + 1)}
+{-# inline forIx #-}
diff --git a/Data/Array/Dynamic/U.hs b/Data/Array/Dynamic/U.hs
new file mode 100644
--- /dev/null
+++ b/Data/Array/Dynamic/U.hs
@@ -0,0 +1,237 @@
+{-# language
+   RankNTypes, LambdaCase, KindSignatures, RoleAnnotations, BangPatterns,
+   GeneralizedNewtypeDeriving, UndecidableInstances #-}
+
+{-|
+Arrays of unlifted elements.
+-}
+
+module Data.Array.Dynamic.U  (
+    empty
+  , Array(..)
+  , capacity
+  , clear
+  , push
+  , pop
+  , Data.Array.Dynamic.U.read
+  , Data.Array.Dynamic.U.show
+  , size
+  , unsafeRead
+  , unsafeWrite
+  , write
+  , unsafeLast
+  , Data.Array.Dynamic.U.last
+  , isEmpty
+  , Data.Array.Dynamic.U.foldl'
+  , foldlIx'
+  , foldr'
+  , foldrIx'
+  , fromList
+  , freeze
+  , for
+  , forIx
+  ) where
+
+import Data.Unlifted
+import Data.Internal.Errors
+import Data.Kind
+
+import qualified Data.Ref.UU   as RUU
+import qualified Data.Ref.F    as RF
+import qualified Data.Array.UM as UM
+import qualified Data.Array.UI as UI
+
+type role Array representational
+newtype Array (a :: Type) = Array (RUU.Ref (RF.Ref Int) (UM.Array a))
+  deriving Unlifted
+
+defaultCapacity :: Int
+defaultCapacity = 5
+{-# inline defaultCapacity #-}
+
+empty :: forall a. Unlifted a => IO (Array a)
+empty = do
+  sizeRef <- RF.new 0
+  arrRef  <- UM.new defaultCapacity defaultElem
+  Array <$> RUU.new sizeRef arrRef
+{-# inline empty #-}
+
+capacity :: Array a -> IO Int
+capacity (Array r) = do
+  elems <- RUU.readSnd r
+  pure $! UM.size elems
+{-# inline capacity #-}
+
+unsafeRead :: Unlifted a => Array a -> Int -> IO a
+unsafeRead (Array r) i = do
+  elems <- RUU.readSnd r
+  UM.read elems i
+{-# inline unsafeRead #-}
+
+read :: Unlifted a => Array a -> Int -> IO a
+read (Array r) i = do
+  elems <- RUU.readSnd r
+  sizeRef <- RUU.readFst r
+  size <- RF.read sizeRef
+  if 0 <= i && i < size then
+    UM.read elems i
+  else
+    error "Data.Array.Dynamic.U.read: out of bounds"
+{-# inline read #-}
+
+unsafeWrite :: Unlifted a => Array a -> Int -> a -> IO ()
+unsafeWrite (Array r) i a = do
+  elems <- RUU.readSnd r
+  UM.write elems i a
+{-# inline unsafeWrite #-}
+
+write :: Unlifted a => Array a -> Int -> a -> IO ()
+write (Array r) i ~a = do
+  s <- RF.read =<< RUU.readFst r
+  if 0 <= i && i < s
+    then unsafeWrite (Array r) i a
+    else error "Data.Array.Dynamic.U.write: out of bounds"
+{-# inline write #-}
+
+push :: Unlifted a => Array a -> a -> IO ()
+push (Array r) ~a = do
+  sizeRef <- RUU.readFst r
+  elems   <- RUU.readSnd r
+  size    <- RF.read sizeRef
+  let cap = UM.size elems
+  RF.write sizeRef (size + 1)
+  if (size == cap) then do
+    let cap' = 2 * cap
+    elems' <- UM.new cap' undefElem
+    UM.copySlice elems 0 elems' 0 size
+    UM.write elems' size a
+    RUU.writeSnd r elems'
+  else do
+    UM.write elems size a
+{-# inline push #-}
+
+pop :: Unlifted a => Array a -> IO (Maybe a)
+pop (Array r) = do
+  sizeRef <- RUU.readFst r
+  size    <- RF.read sizeRef
+  case size of
+    0    -> pure Nothing
+    size -> do
+      elems <- RUU.readSnd r
+      let size' = size - 1
+      a <- UM.read elems size'
+      UM.write elems size' undefElem
+      RF.write sizeRef size'
+      pure $! Just a
+{-# inline pop #-}
+
+fromList :: Unlifted a => [a] -> IO (Array a)
+fromList as = do
+  let size = length as
+      cap  = size + defaultCapacity
+  sizeRef <- RF.new size
+  arrRef  <- UM.new cap defaultElem
+  arr     <- RUU.new sizeRef arrRef
+  let go !i []     = pure ()
+      go i  (a:as) = UM.write arrRef i a >> go (i + 1) as
+  go 0 as
+  pure (Array arr)
+
+freeze :: Unlifted a => Array a -> IO (UI.Array a)
+freeze (Array arr) = do
+  sizeRef <- RUU.readFst arr
+  elems   <- RUU.readSnd arr
+  size    <- RF.read sizeRef
+  tgt     <- UM.new size defaultElem
+  UM.copySlice elems 0 tgt 0 size
+  UM.unsafeFreeze tgt
+
+clear :: Unlifted a => Array a -> IO ()
+clear (Array r) = do
+  (`RF.write` 0) =<< RUU.readFst r
+  RUU.writeSnd r =<< UM.new defaultCapacity undefElem
+{-# inline clear #-}
+
+size :: Array a -> IO Int
+size (Array r) = RF.read =<< RUU.readFst r
+{-# inline size #-}
+
+unsafeLast :: Unlifted a => Array a -> IO a
+unsafeLast arr = do
+  i <- size arr
+  Data.Array.Dynamic.U.unsafeRead arr (i - 1)
+{-# inline unsafeLast #-}
+
+isEmpty :: Array a -> IO Bool
+isEmpty arr = (==0) <$> size arr
+{-# inline isEmpty #-}
+
+last :: Unlifted a => Array a -> IO a
+last arr = do
+  i <- size arr
+  isEmpty arr >>= \case
+    True -> error "Data.Array.Dynamic.U.last: empty array"
+    _    -> unsafeRead arr (i - 1)
+{-# inline last #-}
+
+show :: (Show a, Unlifted a) => Array a -> IO String
+show (Array r) = do
+  elems  <- RUU.readSnd r
+  size <- RF.read =<< RUU.readFst r
+  elems' <- UM.freezeSlice elems 0 size
+  pure (Prelude.show elems')
+{-# inlinable show #-}
+
+foldl' :: Unlifted a => (b -> a -> b) -> b -> Array a -> IO b
+foldl' f b = \arr -> do
+  s <- size arr
+  let go i b | i == s    = pure b
+             | otherwise = do
+                 a <- unsafeRead arr i
+                 go (i + 1) $! f b a
+  go 0 b
+{-# inline foldl' #-}
+
+foldlIx' :: Unlifted a => (Int -> b -> a -> b) -> b -> Array a -> IO b
+foldlIx' f b = \arr -> do
+  s <- size arr
+  let go i b | i == s    = pure b
+             | otherwise = do
+                 a <- unsafeRead arr i
+                 go (i + 1) $! f i b a
+  go 0 b
+{-# inline foldlIx' #-}
+
+foldr' :: Unlifted a => (a -> b -> b) -> b -> Array a -> IO b
+foldr' f b = \arr -> do
+  s <- size arr
+  let go i b | i == (-1) = pure b
+             | otherwise = do
+                 a <- unsafeRead arr i
+                 go (i - 1) $! f a b
+  go (s - 1) b
+{-# inline foldr' #-}
+
+foldrIx' :: Unlifted a => (Int -> a -> b -> b) -> b -> Array a -> IO b
+foldrIx' f b = \arr -> do
+  s <- size arr
+  let go i b | i == (-1) = pure b
+             | otherwise = do
+                 a <- unsafeRead arr i
+                 go (i - 1) $! f i a b
+  go (s - 1) b
+{-# inline foldrIx' #-}
+
+for :: Unlifted a => Array a -> (a -> IO b) -> IO ()
+for arr f = go (0 :: Int) where
+  go i = do
+    s <- size arr
+    if i == s then pure () else do {x <- unsafeRead arr i; f x; go (i + 1)}
+{-# inline for #-}
+
+forIx :: Unlifted a => Array a -> (Int -> a -> IO b) -> IO ()
+forIx arr f = go (0 :: Int) where
+  go i = do
+    s <- size arr
+    if i == s then pure () else do {x <- unsafeRead arr i; f i x; go (i + 1)}
+{-# inline forIx #-}
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,18 @@
+Copyright 2025 András Kovács
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/dynamic-array.cabal b/dynamic-array.cabal
new file mode 100644
--- /dev/null
+++ b/dynamic-array.cabal
@@ -0,0 +1,31 @@
+cabal-version: 1.12
+
+-- This file has been generated from package.yaml by hpack version 0.38.1.
+--
+-- see: https://github.com/sol/hpack
+
+name:           dynamic-array
+version:        0.1.3
+synopsis:       Minimum-overhead mutable dynamic arrays
+category:       data
+author:         András Kovács
+maintainer:     puttamalac@gmail.com
+copyright:      2018-2021 András Kovács
+license:        MIT
+license-file:   LICENSE.txt
+build-type:     Simple
+
+library
+  exposed-modules:
+      Data.Array.Dynamic.F
+      Data.Array.Dynamic.L
+      Data.Array.Dynamic.U
+  other-modules:
+      Paths_dynamic_array
+  hs-source-dirs:
+      ./
+  ghc-options: -Wall -Wno-missing-signatures -Wno-name-shadowing -Wno-unused-do-bind -Wno-unused-matches -Wno-partial-type-signatures -O2
+  build-depends:
+      base >=4.7 && <5
+    , primdata <0.2
+  default-language: Haskell2010
