You may want to use the Hackage page of the Data.Primitive.Array module: https://hackage.haskell.org/package/primitive-0.8.0.0/docs/Data-Primitive-Array.html
Some relevant functions:
createArray :: Int -> a -> (forall s. MutableArray s a -> ST s ()) -> Array a
Create an array of the given size with a default value, apply the monadic function and freeze the result. If the size is 0, return emptyArray (rather than a new copy thereof).
createArray 0 _ _ = emptyArray createArray n x f = runArray $ do mary <- newArray n x f mary pure mary
thawArray :: PrimMonad m => Array a -- ^ source -> Int -- ^ offset -> Int -- ^ length -> m (MutableArray (PrimState m) a)
Create a mutable array from a slice of an immutable array.
This operation makes a copy of the specified slice, so it is safe to use the immutable array afterward.
Note: The provided array should contain the full subrange specified by the two Ints, but this is not checked.