diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,18 @@
+# 0.4.1
+
+* Introduction of `Stream` and `DS` representation:
+  * `filterS`, `filterM`, `ifilterS`, `ifilterM`
+  * `mapMaybeS`, `mapMaybeM`, `imapMaybeS`, `imapMaybeM`
+  * `unfoldr`, `unfoldrN`
+  * `takeS` and `dropS`
+* Deprecated `traverseAR`, `itraverseAR`, `traversePrimR`, `itraversePrimR` (not feasible
+  to keep duplicate functions just for representation, `TypeApplications` or
+  `ScopedVariables` should be used instead.)
+* Fix performance issue with copying of unboxed arrays and initialization of storable array.
+* Addition of `unsafeLoadIntoS`, `unsafeLoadInto` and `maxSize`
+* Addition of `reverse`, `reverse'` and `reverseM`
+* Addition of `modifyDimension`, `modifyDimM`, and `modifyDim'`
+
 # 0.4.0
 
 * Made `Construct` a super class of `Mutable`
diff --git a/massiv.cabal b/massiv.cabal
--- a/massiv.cabal
+++ b/massiv.cabal
@@ -1,5 +1,5 @@
 name:                massiv
-version:             0.4.0.0
+version:             0.4.1.0
 synopsis:            Massiv (Массив) is an Array Library.
 description:         Multi-dimensional Arrays with fusion, stencils and parallel computation.
 homepage:            https://github.com/lehins/massiv
@@ -32,6 +32,7 @@
                      , Data.Massiv.Array.Delayed
                      , Data.Massiv.Array.Manifest
                      , Data.Massiv.Array.Manifest.Vector
+                     , Data.Massiv.Array.Manifest.Vector.Stream
                      , Data.Massiv.Array.Mutable
                      , Data.Massiv.Array.Mutable.Algorithms
                      , Data.Massiv.Array.Mutable.Atomic
@@ -48,6 +49,7 @@
   other-modules:       Data.Massiv.Array.Delayed.Interleaved
                      , Data.Massiv.Array.Delayed.Pull
                      , Data.Massiv.Array.Delayed.Push
+                     , Data.Massiv.Array.Delayed.Stream
                      , Data.Massiv.Array.Delayed.Windowed
                      , Data.Massiv.Array.Manifest.Boxed
                      , Data.Massiv.Array.Manifest.Internal
diff --git a/src/Data/Massiv/Array.hs b/src/Data/Massiv/Array.hs
--- a/src/Data/Massiv/Array.hs
+++ b/src/Data/Massiv/Array.hs
@@ -49,6 +49,10 @@
 --         as /Push/ array. Useful for fusing various array combining functions. Use `computeAs` in
 --         order to load array into `Manifest` representation.
 --
+-- * `DS` - delayed stream vector representation that describes how to handle a vector with
+--         possibility of unknown length. Useful for filtering and unfolding. Use `computeAs`
+--         in order to load such vector into `Manifest` representation.
+--
 -- * `DI` - delayed interleaved array. Same as `D`, but performs better with unbalanced
 --         computation, when evaluation of one element takes much longer than of its neighbor.
 --
@@ -108,6 +112,17 @@
   , evaluate'
   -- * Mapping
   , module Data.Massiv.Array.Ops.Map
+  -- * Filtering
+  -- ** Maybe
+  , mapMaybeS
+  , imapMaybeS
+  , mapMaybeM
+  , imapMaybeM
+  -- ** Predicate
+  , filterS
+  , ifilterS
+  , filterM
+  , ifilterM
   -- * Folding
 
   -- $folding
@@ -138,6 +153,7 @@
   ) where
 
 import Data.Massiv.Array.Delayed
+import Data.Massiv.Array.Delayed.Stream
 import Data.Massiv.Array.Manifest
 import Data.Massiv.Array.Manifest.Internal
 import Data.Massiv.Array.Manifest.List
@@ -153,8 +169,53 @@
 import Data.Massiv.Core
 import Data.Massiv.Core.Common
 import Prelude as P hiding (all, and, any, enumFromTo, foldl, foldr, mapM,
-                     mapM_, maximum, minimum, or, product, replicate, splitAt,
-                     sum, zip)
+                            mapM_, maximum, minimum, or, product, replicate, splitAt,
+                            sum, zip)
+
+
+-- | Similar to `mapMaybeM`, but map with an index aware function.
+--
+-- @since 0.4.1
+imapMaybeS :: Source r ix a => (ix -> a -> Maybe b) -> Array r ix a -> Array DS Ix1 b
+imapMaybeS f arr =
+  mapMaybeS (uncurry f) $ makeArrayR D (getComp arr) (size arr) $ \ ix -> (ix, unsafeIndex arr ix)
+{-# INLINE imapMaybeS #-}
+
+-- | Similar to `mapMaybeM`, but map with an index aware function.
+--
+-- @since 0.4.1
+imapMaybeM ::
+     (Source r ix a, Applicative f) => (ix -> a -> f (Maybe b)) -> Array r ix a -> f (Array DS Ix1 b)
+imapMaybeM f arr =
+  mapMaybeM (uncurry f) $ makeArrayR D (getComp arr) (size arr) $ \ ix -> (ix, unsafeIndex arr ix)
+{-# INLINE imapMaybeM #-}
+
+-- | Similar to `filterS`, but map with an index aware function.
+--
+-- @since 0.4.1
+ifilterS :: Source r ix a => (ix -> a -> Bool) -> Array r ix a -> Array DS Ix1 a
+ifilterS f =
+  imapMaybeS $ \ix e ->
+    if f ix e
+      then Just e
+      else Nothing
+{-# INLINE ifilterS #-}
+
+
+-- | Similar to `filterM`, but map with an index aware function.
+--
+-- @since 0.4.1
+ifilterM ::
+     (Source r ix a, Applicative f) => (ix -> a -> f Bool) -> Array r ix a -> f (Array DS Ix1 a)
+ifilterM f =
+  imapMaybeM $ \ix e ->
+    (\p ->
+       if p
+         then Just e
+         else Nothing) <$>
+    f ix e
+{-# INLINE ifilterM #-}
+
 
 {- $folding
 
diff --git a/src/Data/Massiv/Array/Delayed.hs b/src/Data/Massiv/Array/Delayed.hs
--- a/src/Data/Massiv/Array/Delayed.hs
+++ b/src/Data/Massiv/Array/Delayed.hs
@@ -17,6 +17,11 @@
   , makeLoadArrayS
   , makeLoadArray
   , fromStrideLoad
+  -- ** Delayed Stream Array
+  , DS(..)
+  , toStreamArray
+  , toSteps
+  , fromSteps
   -- ** Delayed Interleaved Array
   , DI(..)
   , toInterleaved
@@ -33,4 +38,5 @@
 import Data.Massiv.Array.Delayed.Interleaved
 import Data.Massiv.Array.Delayed.Pull
 import Data.Massiv.Array.Delayed.Push
+import Data.Massiv.Array.Delayed.Stream
 import Data.Massiv.Array.Delayed.Windowed
diff --git a/src/Data/Massiv/Array/Delayed/Pull.hs b/src/Data/Massiv/Array/Delayed/Pull.hs
--- a/src/Data/Massiv/Array/Delayed/Pull.hs
+++ b/src/Data/Massiv/Array/Delayed/Pull.hs
@@ -25,6 +25,7 @@
 
 import qualified Data.Foldable as F
 import Data.Massiv.Array.Ops.Fold.Internal as A
+import Data.Massiv.Array.Manifest.Vector.Stream as S (steps)
 import Data.Massiv.Core.Common
 import Data.Massiv.Core.Operations
 import Data.Massiv.Core.List (L, showArrayList, showsArrayPrec)
@@ -150,6 +151,11 @@
   {-# INLINE loadArrayM #-}
 
 instance Index ix => StrideLoad D ix e
+
+instance Index ix => Stream D ix e where
+  toStream = S.steps
+  {-# INLINE toStream #-}
+
 
 instance (Index ix, Num e) => Num (Array D ix e) where
   (+)         = unsafeLiftArray2 (+)
diff --git a/src/Data/Massiv/Array/Delayed/Stream.hs b/src/Data/Massiv/Array/Delayed/Stream.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Massiv/Array/Delayed/Stream.hs
@@ -0,0 +1,327 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE TypeFamilies #-}
+-- |
+-- Module      : Data.Massiv.Array.Delayed.Stream
+-- Copyright   : (c) Alexey Kuleshevich 2019
+-- License     : BSD3
+-- Maintainer  : Alexey Kuleshevich <lehins@yandex.ru>
+-- Stability   : experimental
+-- Portability : non-portable
+--
+module Data.Massiv.Array.Delayed.Stream
+  ( DS(..)
+  , Array (..)
+  , toStreamArray
+  , toSteps
+  , fromSteps
+  , takeS
+  , dropS
+  , filterS
+  , filterM
+  , mapMaybeS
+  , mapMaybeM
+  , unfoldr
+  , unfoldrN
+  ) where
+
+import Control.Applicative
+import Control.Monad (void)
+import Data.Coerce
+import Data.Massiv.Array.Delayed.Pull
+import qualified Data.Massiv.Array.Manifest.Vector.Stream as S
+import Data.Massiv.Core.Common
+import GHC.Exts
+import Prelude hiding (take, drop)
+
+-- | Delayed array that will be loaded in an interleaved fashion during parallel
+-- computation.
+data DS = DS
+
+newtype instance Array DS Ix1 e = DSArray
+  { dsArray :: S.Steps S.Id e
+  }
+
+-- | /O(1)/ - Convert delayed stream arrray into `Steps`.
+--
+-- @since 0.4.1
+toSteps :: Array DS Ix1 e -> Steps Id e
+toSteps = coerce
+{-# INLINE toSteps #-}
+
+-- | /O(1)/ - Convert `Steps` into delayed stream arrray
+--
+-- @since 0.4.1
+fromSteps :: Steps Id e -> Array DS Ix1 e
+fromSteps = coerce
+{-# INLINE fromSteps #-}
+
+
+instance Functor (Array DS Ix1) where
+
+  fmap f = coerce . fmap f . dsArray
+  {-# INLINE fmap #-}
+
+instance Applicative (Array DS Ix1) where
+
+  pure = fromSteps . S.singleton
+  {-# INLINE pure #-}
+
+  (<*>) a1 a2 = fromSteps (S.zipWith ($) (coerce a1) (coerce a2))
+  {-# INLINE (<*>) #-}
+
+#if MIN_VERSION_base(4,10,0)
+  liftA2 f a1 a2 = fromSteps (S.zipWith f (coerce a1) (coerce a2))
+  {-# INLINE liftA2 #-}
+#endif
+
+instance Monad (Array DS Ix1) where
+
+  return = fromSteps . S.singleton
+  {-# INLINE return #-}
+
+  (>>=) arr f = coerce (S.concatMap (coerce . f) (dsArray arr))
+  {-# INLINE (>>=) #-}
+
+
+instance Foldable (Array DS Ix1) where
+
+  foldr f acc = S.foldr f acc . toSteps
+  {-# INLINE foldr #-}
+
+  length = S.length . coerce
+  {-# INLINE length #-}
+
+  -- TODO: add more
+
+
+instance Semigroup (Array DS Ix1 e) where
+
+  (<>) a1 a2 = fromSteps (coerce a1 `S.append` coerce a2)
+  {-# INLINE (<>) #-}
+
+
+instance Monoid (Array DS Ix1 e) where
+
+  mempty = DSArray S.empty
+  {-# INLINE mempty #-}
+
+  mappend = (<>)
+  {-# INLINE mappend #-}
+
+instance IsList (Array DS Ix1 e) where
+  type Item (Array DS Ix1 e) = e
+
+  fromList = fromSteps . S.fromList
+  {-# INLINE fromList #-}
+
+  fromListN n = fromSteps . S.fromListN n
+  {-# INLINE fromListN #-}
+
+  toList = S.toList . coerce
+  {-# INLINE toList #-}
+
+
+instance S.Stream DS Ix1 e where
+  toStream = coerce
+  {-# INLINE toStream #-}
+
+
+-- | Flatten an array into a stream of values.
+--
+-- @since 0.4.1
+toStreamArray :: Source r ix e => Array r ix e -> Array DS Ix1 e
+toStreamArray = DSArray . S.steps
+{-# INLINE toStreamArray #-}
+
+instance Construct DS Ix1 e where
+  setComp _ arr = arr
+  {-# INLINE setComp #-}
+
+  makeArrayLinear _ (Sz k) = fromSteps . S.generate k
+  {-# INLINE makeArrayLinear #-}
+
+
+instance Extract DS Ix1 e where
+  unsafeExtract sIx newSz = fromSteps . S.slice sIx (unSz newSz) . dsArray
+  {-# INLINE unsafeExtract #-}
+
+-- | /O(n)/ - `size` implementation.
+instance Load DS Ix1 e where
+  size = SafeSz . S.length . coerce
+  {-# INLINE size #-}
+
+  getComp _ = Seq
+  {-# INLINE getComp #-}
+
+  loadArrayM _scheduler arr uWrite =
+    case stepsSize (dsArray arr) of
+      S.Exact _ ->
+        void $ S.foldlM (\i e -> uWrite i e >> pure (i + 1)) 0 (S.transStepsId (coerce arr))
+      _ -> error "Loading Stream array is not supported with loadArrayM"
+  {-# INLINE loadArrayM #-}
+
+  unsafeLoadIntoS marr (DSArray sts) =
+    S.unstreamIntoM marr (stepsSize sts) (stepsStream sts)
+  {-# INLINE unsafeLoadIntoS #-}
+
+  unsafeLoadInto marr arr = liftIO $ unsafeLoadIntoS marr arr
+  {-# INLINE unsafeLoadInto #-}
+
+
+-- cons :: e -> Array DS Ix1 e -> Array DS Ix1 e
+-- cons e = coerce . S.cons e . dsArray
+-- {-# INLINE cons #-}
+
+-- uncons :: Array DS Ix1 e -> Maybe (e, Array DS Ix1 e)
+-- uncons = coerce . S.uncons . dsArray
+-- {-# INLINE uncons #-}
+
+-- snoc :: Array DS Ix1 e -> e -> Array DS Ix1 e
+-- snoc (DSArray sts) e = DSArray (S.snoc sts e)
+-- {-# INLINE snoc #-}
+
+
+-- TODO: skip the stride while loading
+-- instance StrideLoad DS Ix1 e where
+--   loadArrayWithStrideM scheduler stride resultSize arr uWrite =
+--     let strideIx = unStride stride
+--         DIArray (DArray _ _ f) = arr
+--     in loopM_ 0 (< numWorkers scheduler) (+ 1) $ \ !start ->
+--           scheduleWork scheduler $
+--           iterLinearM_ resultSize start (totalElem resultSize) (numWorkers scheduler) (<) $
+--             \ !i ix -> uWrite i (f (liftIndex2 (*) strideIx ix))
+--   {-# INLINE loadArrayWithStrideM #-}
+
+
+-- | Right unfolding function. Useful when we do not have any idea ahead of time on how
+-- many elements the vector will have.
+--
+-- ====__Example__
+--
+-- >>> import Data.Massiv.Array as A
+-- >>> unfoldr (\i -> if i < 9 then Just (i*i, i + 1) else Nothing) (0 :: Int)
+-- Array DS Seq (Sz1 9)
+--   [ 0, 1, 4, 9, 16, 25, 36, 49, 64 ]
+-- >>> unfoldr (\i -> if sqrt i < 3 then Just (i * i, i + 1) else Nothing) (0 :: Double)
+-- Array DS Seq (Sz1 9)
+--   [ 0.0, 1.0, 4.0, 9.0, 16.0, 25.0, 36.0, 49.0, 64.0 ]
+--
+-- @since 0.4.1
+unfoldr :: (s -> Maybe (e, s)) -> s -> Array DS Ix1 e
+unfoldr f = DSArray . S.unfoldr f
+{-# INLINE unfoldr #-}
+
+
+-- | Right unfolding function with limited number of elements.
+--
+-- ==== __Example__
+--
+-- >>> import Data.Massiv.Array as A
+-- >>> unfoldrN 9 (\i -> Just (i*i, i + 1)) (0 :: Int)
+-- Array DS Seq (Sz1 9)
+--   [ 0, 1, 4, 9, 16, 25, 36, 49, 64 ]
+--
+-- @since 0.4.1
+unfoldrN ::
+     Sz1
+  -- ^ Maximum number of elements that the vector can have
+  -> (s -> Maybe (e, s))
+  -- ^ Unfolding function. Stops when `Nothing` is reaturned or maximum number of elements
+  -- is reached.
+  -> s -- ^ Inititial element.
+  -> Array DS Ix1 e
+unfoldrN n f = DSArray . S.unfoldrN n f
+{-# INLINE unfoldrN #-}
+
+-- | Sequentially filter out elements from the array according to the supplied predicate.
+--
+-- ==== __Example__
+--
+-- >>> import Data.Massiv.Array as A
+-- >>> arr = makeArrayR D Seq (Sz2 3 4) fromIx2
+-- >>> arr
+-- Array D Seq (Sz (3 :. 4))
+--   [ [ (0,0), (0,1), (0,2), (0,3) ]
+--   , [ (1,0), (1,1), (1,2), (1,3) ]
+--   , [ (2,0), (2,1), (2,2), (2,3) ]
+--   ]
+-- >>> filterS (even . fst) arr
+-- Array DS Seq (Sz1 8)
+--   [ (0,0), (0,1), (0,2), (0,3), (2,0), (2,1), (2,2), (2,3) ]
+--
+-- @since 0.4.1
+filterS :: S.Stream r ix e => (e -> Bool) -> Array r ix e -> Array DS Ix1 e
+filterS f = DSArray . S.filter f . S.toStream
+{-# INLINE filterS #-}
+
+-- | Sequentially filter out elements from the array according to the supplied applicative predicate.
+--
+-- ==== __Example__
+--
+-- >>> import Data.Massiv.Array as A
+-- >>> arr = makeArrayR D Seq (Sz2 3 4) fromIx2
+-- >>> arr
+-- Array D Seq (Sz (3 :. 4))
+--   [ [ (0,0), (0,1), (0,2), (0,3) ]
+--   , [ (1,0), (1,1), (1,2), (1,3) ]
+--   , [ (2,0), (2,1), (2,2), (2,3) ]
+--   ]
+-- >>> filterM (Just . odd . fst) arr
+-- Just (Array DS Seq (Sz1 4)
+--   [ (1,0), (1,1), (1,2), (1,3) ]
+-- )
+-- >>> filterM (\ix@(_, j) -> print ix >> return (even j)) arr
+-- (0,0)
+-- (0,1)
+-- (0,2)
+-- (0,3)
+-- (1,0)
+-- (1,1)
+-- (1,2)
+-- (1,3)
+-- (2,0)
+-- (2,1)
+-- (2,2)
+-- (2,3)
+-- Array DS Seq (Sz1 6)
+--   [ (0,0), (0,2), (1,0), (1,2), (2,0), (2,2) ]
+--
+-- @since 0.4.1
+filterM :: (S.Stream r ix e, Applicative f) => (e -> f Bool) -> Array r ix e -> f (Array DS Ix1 e)
+filterM f arr = DSArray <$> S.filterA f (S.toStream arr)
+{-# INLINE filterM #-}
+
+
+-- | Apply a function to each element of the array, while discarding `Nothing` and
+-- keepingt he `Maybe` result.
+--
+-- @since 0.4.1
+mapMaybeS :: S.Stream r ix a => (a -> Maybe b) -> Array r ix a -> Array DS Ix1 b
+mapMaybeS f = DSArray . S.mapMaybe f . S.toStream
+{-# INLINE mapMaybeS #-}
+
+
+-- | Similar to `mapMaybeS`, but with the use of `Applicative`
+--
+-- @since 0.4.1
+mapMaybeM ::
+     (S.Stream r ix a, Applicative f) => (a -> f (Maybe b)) -> Array r ix a -> f (Array DS Ix1 b)
+mapMaybeM f arr = DSArray <$> S.mapMaybeA f (S.toStream arr)
+{-# INLINE mapMaybeM #-}
+
+-- | Extract first @n@ elements from the stream vector
+--
+-- @since 0.4.1
+takeS :: Stream r ix e => Sz1 -> Array r ix e -> Array DS Ix1 e
+takeS n = fromSteps . S.take (unSz n) . S.toStream
+{-# INLINE takeS #-}
+
+-- | Keep all but first @n@ elements from the stream vector.
+--
+-- @since 0.4.1
+dropS :: Stream r ix e => Sz1 -> Array r ix e -> Array DS Ix1 e
+dropS n = fromSteps . S.drop (unSz n) . S.toStream
+{-# INLINE dropS #-}
diff --git a/src/Data/Massiv/Array/Manifest/Boxed.hs b/src/Data/Massiv/Array/Manifest/Boxed.hs
--- a/src/Data/Massiv/Array/Manifest/Boxed.hs
+++ b/src/Data/Massiv/Array/Manifest/Boxed.hs
@@ -42,8 +42,10 @@
 import qualified Data.Foldable as F (Foldable(..))
 import Data.Massiv.Array.Delayed.Pull (eq, ord)
 import Data.Massiv.Array.Delayed.Push (DL)
+import Data.Massiv.Array.Delayed.Stream (DS)
 import Data.Massiv.Array.Manifest.Internal (M, computeAs, toManifest)
 import Data.Massiv.Array.Manifest.List as L
+import Data.Massiv.Array.Manifest.Vector.Stream as S (steps)
 import Data.Massiv.Array.Mutable
 import Data.Massiv.Array.Ops.Fold
 import Data.Massiv.Array.Ops.Fold.Internal
@@ -91,7 +93,11 @@
   showsPrec = showsArrayPrec (computeAs B)
   showList = showArrayList
 
+instance Show e => Show (Array DS Ix1 e) where
+  showsPrec = showsArrayPrec (computeAs B)
+  showList = showArrayList
 
+
 instance (Index ix, NFData e) => NFData (Array B ix e) where
   rnf = (`deepseqArray` ())
   {-# INLINE rnf #-}
@@ -193,7 +199,11 @@
 
 instance Index ix => StrideLoad B ix e
 
+instance Index ix => Stream B ix e where
+  toStream = S.steps
+  {-# INLINE toStream #-}
 
+
 -- | Row-major sequential folding over a Boxed array.
 instance Index ix => Foldable (Array B ix) where
   fold = fold
@@ -361,6 +371,9 @@
 
 instance (Index ix, NFData e) => StrideLoad N ix e
 
+instance Index ix => Stream N ix e where
+  toStream = toStream . coerce
+  {-# INLINE toStream #-}
 
 
 instance ( NFData e
diff --git a/src/Data/Massiv/Array/Manifest/Internal.hs b/src/Data/Massiv/Array/Manifest/Internal.hs
--- a/src/Data/Massiv/Array/Manifest/Internal.hs
+++ b/src/Data/Massiv/Array/Manifest/Internal.hs
@@ -48,6 +48,7 @@
 import Data.Massiv.Array.Delayed.Pull
 import Data.Massiv.Array.Mutable
 import Data.Massiv.Array.Ops.Fold.Internal
+import Data.Massiv.Array.Manifest.Vector.Stream as S (steps)
 import Data.Massiv.Core.Common
 import Data.Massiv.Core.List
 import Data.Maybe (fromMaybe)
@@ -191,6 +192,10 @@
   {-# INLINE loadArrayM #-}
 
 instance Index ix => StrideLoad M ix e
+
+instance Index ix => Stream M ix e where
+  toStream = S.steps
+  {-# INLINE toStream #-}
 
 
 -- | Ensure that Array is computed, i.e. represented with concrete elements in memory, hence is the
diff --git a/src/Data/Massiv/Array/Manifest/List.hs b/src/Data/Massiv/Array/Manifest/List.hs
--- a/src/Data/Massiv/Array/Manifest/List.hs
+++ b/src/Data/Massiv/Array/Manifest/List.hs
@@ -31,7 +31,7 @@
 import Data.Massiv.Array.Ops.Fold.Internal (foldrFB)
 import Data.Massiv.Core.Common
 import Data.Massiv.Core.List
-import GHC.Base (build)
+import GHC.Exts (build)
 
 -- | Convert a flat list into a vector
 --
diff --git a/src/Data/Massiv/Array/Manifest/Primitive.hs b/src/Data/Massiv/Array/Manifest/Primitive.hs
--- a/src/Data/Massiv/Array/Manifest/Primitive.hs
+++ b/src/Data/Massiv/Array/Manifest/Primitive.hs
@@ -44,6 +44,7 @@
 import Data.Massiv.Array.Delayed.Pull (eq, ord)
 import Data.Massiv.Array.Manifest.Internal
 import Data.Massiv.Array.Manifest.List as A
+import Data.Massiv.Array.Manifest.Vector.Stream as S (steps)
 import Data.Massiv.Array.Mutable
 import Data.Massiv.Core.Common
 import Data.Massiv.Core.List
@@ -223,6 +224,10 @@
   {-# INLINE loadArrayM #-}
 
 instance (Prim e, Index ix) => StrideLoad P ix e
+
+instance (Prim e, Index ix) => Stream P ix e where
+  toStream = S.steps
+  {-# INLINE toStream #-}
 
 instance ( Prim e
          , IsList (Array L ix e)
diff --git a/src/Data/Massiv/Array/Manifest/Storable.hs b/src/Data/Massiv/Array/Manifest/Storable.hs
--- a/src/Data/Massiv/Array/Manifest/Storable.hs
+++ b/src/Data/Massiv/Array/Manifest/Storable.hs
@@ -39,6 +39,7 @@
 import Data.Massiv.Array.Manifest.Primitive (shrinkMutableByteArray)
 import Data.Primitive.ByteArray (MutableByteArray(..))
 import Data.Massiv.Array.Manifest.List as A
+import Data.Massiv.Array.Manifest.Vector.Stream as S (steps)
 import Data.Massiv.Array.Mutable
 import Data.Massiv.Core.Common
 import Data.Massiv.Core.List
@@ -161,9 +162,8 @@
     INDEX_CHECK("(Mutable S ix e).unsafeLinearWrite", Sz . MVS.length, MVS.unsafeWrite) mv
   {-# INLINE unsafeLinearWrite #-}
 
-  -- TODO: Try approach from `vector`, fallback on Prim for setByteArray/recursive copyArray
-  -- unsafeLinearSet (MSArray _ v) = setByteArray ma
-  -- {-# INLINE unsafeLinearSet #-}
+  unsafeLinearSet (MSArray _ mv) i k = VGM.basicSet (MVS.unsafeSlice i (unSz k) mv)
+  {-# INLINE unsafeLinearSet #-}
 
   unsafeLinearCopy marrFrom iFrom marrTo iTo (Sz k) = do
     let MSArray _ (MVS.MVector _ fpFrom) = marrFrom
@@ -209,6 +209,10 @@
   {-# INLINE loadArrayM #-}
 
 instance (Index ix, VS.Storable e) => StrideLoad S ix e
+
+instance (Index ix, VS.Storable e) => Stream S ix e where
+  toStream = S.steps
+  {-# INLINE toStream #-}
 
 
 instance ( VS.Storable e
diff --git a/src/Data/Massiv/Array/Manifest/Unboxed.hs b/src/Data/Massiv/Array/Manifest/Unboxed.hs
--- a/src/Data/Massiv/Array/Manifest/Unboxed.hs
+++ b/src/Data/Massiv/Array/Manifest/Unboxed.hs
@@ -27,6 +27,7 @@
 import Data.Massiv.Array.Delayed.Pull (eq, ord)
 import Data.Massiv.Array.Manifest.Internal (M, toManifest)
 import Data.Massiv.Array.Manifest.List as A
+import Data.Massiv.Array.Manifest.Vector.Stream as S (steps)
 import Data.Massiv.Array.Mutable
 import Data.Massiv.Core.Common
 import Data.Massiv.Core.List
@@ -168,6 +169,10 @@
   initialize (MUArray _ marr) = VGM.basicInitialize marr
   {-# INLINE initialize #-}
 
+  unsafeLinearCopy (MUArray _ mvFrom) iFrom (MUArray _ mvTo) iTo (Sz k) =
+    MVU.unsafeCopy (MVU.unsafeSlice iTo k mvTo) (MVU.unsafeSlice iFrom k mvFrom)
+  {-# INLINE unsafeLinearCopy #-}
+
   unsafeLinearRead (MUArray _ mv) =
     INDEX_CHECK("(Mutable U ix e).unsafeLinearRead", Sz . MVU.length, MVU.unsafeRead) mv
   {-# INLINE unsafeLinearRead #-}
@@ -178,6 +183,12 @@
 
   unsafeLinearGrow (MUArray _ mv) sz = MUArray sz <$> MVU.unsafeGrow mv (totalElem sz)
   {-# INLINE unsafeLinearGrow #-}
+
+
+instance (Index ix, VU.Unbox e) => Stream U ix e where
+  toStream = S.steps
+  {-# INLINE toStream #-}
+
 
 instance ( VU.Unbox e
          , IsList (Array L ix e)
diff --git a/src/Data/Massiv/Array/Manifest/Vector/Stream.hs b/src/Data/Massiv/Array/Manifest/Vector/Stream.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Massiv/Array/Manifest/Vector/Stream.hs
@@ -0,0 +1,410 @@
+{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+-- |
+-- Module      : Data.Massiv.Array.Manifest.Vector.Stream
+-- Copyright   : (c) Alexey Kuleshevich 2019
+-- License     : BSD3
+-- Maintainer  : Alexey Kuleshevich <lehins@yandex.ru>
+-- Stability   : experimental
+-- Portability : non-portable
+--
+module Data.Massiv.Array.Manifest.Vector.Stream
+  ( -- | __Important__ - This module is still experimental, as such it is considered
+    -- internal and exported for the curious users only.
+    Steps(..)
+  , Stream(..)
+  -- * Conversion
+  , steps
+  , isteps
+  , fromStream
+  , fromStreamM
+  , fromStreamExactM
+  , unstreamExact
+  , unstreamMax
+  , unstreamMaxM
+  , unstreamUnknown
+  , unstreamUnknownM
+  , unstreamIntoM
+  -- * Bundle
+  , toBundle
+  , fromBundle
+  , fromBundleM
+  -- * Operations on Steps
+  , length
+  , empty
+  , singleton
+  , generate
+  , cons
+  , uncons
+  , snoc
+  , drop
+  , take
+  , slice
+  , traverse
+  , mapM
+  , concatMap
+  , append
+  , zipWith
+  , zipWithM
+  -- ** Folding
+  , foldl
+  , foldr
+  , foldlM
+  , foldrM
+  -- ** Unfolding
+  , unfoldr
+  , unfoldrN
+  -- * Lists
+  , toList
+  , fromList
+  , fromListN
+  -- ** Filter
+  , mapMaybe
+  , mapMaybeA
+  , mapMaybeM
+  , filter
+  , filterA
+  , filterM
+  , transStepsId
+  -- * Useful re-exports
+  , module Data.Vector.Fusion.Bundle.Size
+  , module Data.Vector.Fusion.Util
+  ) where
+
+import Data.Maybe (catMaybes)
+import qualified Control.Monad as M
+import Control.Monad.ST
+import Data.Massiv.Core.Common hiding (empty, singleton)
+import qualified Data.Traversable as Traversable (traverse)
+import qualified Data.Vector.Fusion.Bundle.Monadic as B
+import Data.Vector.Fusion.Bundle.Size
+import qualified Data.Vector.Fusion.Stream.Monadic as S
+import Data.Vector.Fusion.Util
+import Prelude hiding (zipWith, mapM, traverse, length, foldl, foldr, filter, concatMap, drop, take)
+
+
+
+
+-- TODO: benchmark: `fmap snd . isteps`
+steps :: forall r ix e m . (Monad m, Source r ix e) => Array r ix e -> Steps m e
+steps arr = k `seq` arr `seq` Steps (S.Stream step 0) (Exact k)
+  where
+    k = totalElem $ size arr
+    step i
+      | i < k =
+        let e = unsafeLinearIndex arr i
+         in e `seq` return $ S.Yield e (i + 1)
+      | otherwise = return S.Done
+    {-# INLINE step #-}
+{-# INLINE steps #-}
+
+
+isteps :: forall r ix e m . (Monad m, Source r ix e) => Array r ix e -> Steps m (ix, e)
+isteps arr = k `seq` arr `seq` Steps (S.Stream step 0) (Exact k)
+  where
+    sz = size arr
+    k = totalElem sz
+    step i
+      | i < k =
+        let e = unsafeLinearIndex arr i
+         in e `seq` return $ S.Yield (fromLinearIndex sz i, e) (i + 1)
+      | otherwise = return S.Done
+    {-# INLINE step #-}
+{-# INLINE isteps #-}
+
+toBundle :: (Monad m, Source r ix e) => Array r ix e -> B.Bundle m v e
+toBundle arr =
+  let Steps str k = steps arr
+   in B.fromStream str k
+{-# INLINE toBundle #-}
+
+fromBundle :: Mutable r Ix1 e => B.Bundle Id v e -> Array r Ix1 e
+fromBundle bundle = fromStream (B.sSize bundle) (B.sElems bundle)
+{-# INLINE fromBundle #-}
+
+
+fromBundleM :: (Monad m, Mutable r Ix1 e) => B.Bundle m v e -> m (Array r Ix1 e)
+fromBundleM bundle = fromStreamM (B.sSize bundle) (B.sElems bundle)
+{-# INLINE fromBundleM #-}
+
+
+fromStream :: forall r e . Mutable r Ix1 e => Size -> S.Stream Id e -> Array r Ix1 e
+fromStream sz str =
+  case upperBound sz of
+    Nothing -> unstreamUnknown str
+    Just k  -> unstreamMax k str
+{-# INLINE fromStream #-}
+
+fromStreamM :: forall r e m. (Monad m, Mutable r Ix1 e) => Size -> S.Stream m e -> m (Array r Ix1 e)
+fromStreamM sz str = do
+  xs <- S.toList str
+  case upperBound sz of
+    Nothing -> pure $! unstreamUnknown (S.fromList xs)
+    Just k  -> pure $! unstreamMax k (S.fromList xs)
+{-# INLINE fromStreamM #-}
+
+fromStreamExactM ::
+     forall r ix e m. (Monad m, Mutable r ix e)
+  => Sz ix
+  -> S.Stream m e
+  -> m (Array r ix e)
+fromStreamExactM sz str = do
+  xs <- S.toList str
+  pure $! unstreamExact sz (S.fromList xs)
+{-# INLINE fromStreamExactM #-}
+
+
+unstreamIntoM ::
+     (Mutable r Ix1 a, PrimMonad m)
+  => MArray (PrimState m) r Ix1 a
+  -> Size
+  -> S.Stream Id a
+  -> m (MArray (PrimState m) r Ix1 a)
+unstreamIntoM marr sz str =
+  case sz of
+    Exact _ -> marr <$ unstreamMaxM marr str
+    Max _ -> unsafeLinearShrink marr . SafeSz =<< unstreamMaxM marr str
+    Unknown  -> unstreamUnknownM marr str
+{-# INLINE unstreamIntoM #-}
+
+
+
+unstreamMax ::
+     forall r e. (Mutable r Ix1 e)
+  => Int
+  -> S.Stream Id e
+  -> Array r Ix1 e
+unstreamMax kMax str =
+  runST $ do
+    marr <- unsafeNew (SafeSz kMax)
+    k <- unstreamMaxM marr str
+    unsafeLinearShrink marr (SafeSz k) >>= unsafeFreeze Seq
+{-# INLINE unstreamMax #-}
+
+
+unstreamMaxM ::
+     (Mutable r ix a, PrimMonad m) => MArray (PrimState m) r ix a -> S.Stream Id a -> m Int
+unstreamMaxM marr (S.Stream step s) = stepLoad s 0
+  where
+    stepLoad t i =
+      case unId (step t) of
+        S.Yield e' t' -> do
+          unsafeLinearWrite marr i e'
+          stepLoad t' (i + 1)
+        S.Skip t' -> stepLoad t' i
+        S.Done -> return i
+    {-# INLINE stepLoad #-}
+{-# INLINE unstreamMaxM #-}
+
+
+unstreamUnknown :: Mutable r Ix1 a => S.Stream Id a -> Array r Ix1 a
+unstreamUnknown str =
+  runST $ do
+    let kInit = 1
+    marr <- unsafeNew (SafeSz kInit)
+    unstreamUnknownM marr str >>= unsafeFreeze Seq
+{-# INLINE unstreamUnknown #-}
+
+
+unstreamUnknownM ::
+     (Mutable r Ix1 a, PrimMonad m)
+  => MArray (PrimState m) r Ix1 a
+  -> S.Stream Id a
+  -> m (MArray (PrimState m) r Ix1 a)
+unstreamUnknownM marrInit (S.Stream step s) = stepLoad s 0 (unSz (msize marrInit)) marrInit
+  where
+    stepLoad t i kMax marr
+      | i < kMax =
+        case unId (step t) of
+          S.Yield e' t' -> do
+            unsafeLinearWrite marr i e'
+            stepLoad t' (i + 1) kMax marr
+          S.Skip t' -> stepLoad t' i kMax marr
+          S.Done -> unsafeLinearShrink marr (SafeSz i)
+      | otherwise = do
+        let kMax' = kMax * 2
+        marr' <- unsafeLinearGrow marr (SafeSz kMax')
+        stepLoad t i kMax' marr'
+    {-# INLINE stepLoad #-}
+{-# INLINE unstreamUnknownM #-}
+
+
+unstreamExact ::
+     forall r ix e. (Mutable r ix e)
+  => Sz ix
+  -> S.Stream Id e
+  -> Array r ix e
+unstreamExact sz str =
+  runST $ do
+    marr <- unsafeNew sz
+    _ <- unstreamMaxM marr str
+    unsafeFreeze Seq marr
+{-# INLINE unstreamExact #-}
+
+length :: Steps Id a -> Int
+length (Steps str sz) =
+  case sz of
+    Exact k -> k
+    _       -> unId (S.length str)
+{-# INLINE length #-}
+
+empty :: Monad m => Steps m e
+empty = Steps S.empty (Exact 0)
+{-# INLINE empty #-}
+
+singleton :: Monad m => e -> Steps m e
+singleton e = Steps (S.singleton e) (Exact 1)
+{-# INLINE singleton #-}
+
+generate :: Monad m => Int -> (Int -> e) -> Steps m e
+generate k f = Steps (S.generate k f) (Exact k)
+{-# INLINE generate #-}
+
+cons :: Monad m => e -> Steps m e -> Steps m e
+cons e (Steps str k) = Steps (S.cons e str) (k + 1)
+{-# INLINE cons #-}
+
+uncons :: Monad m => Steps m e -> m (Maybe (e, Steps m e))
+uncons sts@(Steps str _) = do
+  mx <- str S.!? 0
+  pure $ fmap (, drop 1 sts) mx
+{-# INLINE uncons #-}
+
+snoc :: Monad m => Steps m e -> e -> Steps m e
+snoc (Steps str k) e = Steps (S.snoc str e) (k + 1)
+{-# INLINE snoc #-}
+
+traverse :: (Monad m, Applicative f) => (e -> f a) -> Steps Id e -> f (Steps m a)
+traverse f (Steps str k) = (`Steps` k) <$> liftListA (Traversable.traverse f) str
+{-# INLINE traverse #-}
+
+append :: Monad m => Steps m e -> Steps m e -> Steps m e
+append (Steps str1 k1) (Steps str2 k2) = Steps (str1 S.++ str2) (k1 + k2)
+{-# INLINE append #-}
+
+mapM :: Monad m => (e -> m a) -> Steps m e -> Steps m a
+mapM f (Steps str k) = Steps (S.mapM f str) k
+{-# INLINE mapM #-}
+
+zipWith :: Monad m => (a -> b -> e) -> Steps m a -> Steps m b -> Steps m e
+zipWith f (Steps str1 k1) (Steps str2 k2) = Steps (S.zipWith f str1 str2) (smaller k1 k2)
+{-# INLINE zipWith #-}
+
+zipWithM :: Monad m => (a -> b -> m c) -> Steps m a -> Steps m b -> Steps m c
+zipWithM f (Steps str1 k1) (Steps str2 k2) = Steps (S.zipWithM f str1 str2) (smaller k1 k2)
+{-# INLINE zipWithM #-}
+
+transStepsId :: Monad m => Steps Id e -> Steps m e
+transStepsId (Steps sts k) = Steps (S.trans (pure . unId) sts) k
+{-# INLINE transStepsId #-}
+
+
+foldr :: (a -> b -> b) -> b -> Steps Id a -> b
+foldr f acc sts = unId (S.foldr f acc (stepsStream sts))
+{-# INLINE foldr #-}
+
+
+foldl :: (b -> a -> b) -> b -> Steps Id a -> b
+foldl f acc sts = unId (S.foldl f acc (stepsStream sts))
+{-# INLINE foldl #-}
+
+
+foldlM :: Monad m => (a -> b -> m a) -> a -> Steps m b -> m a
+foldlM f acc (Steps sts _) = S.foldlM f acc sts
+{-# INLINE foldlM #-}
+
+
+foldrM :: Monad m => (b -> a -> m a) -> a -> Steps m b -> m a
+foldrM f acc (Steps sts _) = S.foldrM f acc sts
+{-# INLINE foldrM #-}
+
+
+mapMaybe :: Monad m => (a -> Maybe e) -> Steps m a -> Steps m e
+mapMaybe f (Steps str k) = Steps (S.mapMaybe f str) (toMax k)
+{-# INLINE mapMaybe #-}
+
+concatMap :: Monad m => (a -> Steps m e) -> Steps m a -> Steps m e
+concatMap f (Steps str _) = Steps (S.concatMap (stepsStream . f) str) Unknown
+{-# INLINE concatMap #-}
+
+
+mapMaybeA :: (Monad m, Applicative f) => (a -> f (Maybe e)) -> Steps Id a -> f (Steps m e)
+mapMaybeA f (Steps str k) = (`Steps` toMax k) <$> liftListA (mapMaybeListA f) str
+{-# INLINE mapMaybeA #-}
+
+mapMaybeM :: Monad m => (a -> m (Maybe b)) -> Steps m a -> Steps m b
+mapMaybeM f (Steps str k) = Steps (mapMaybeStreamM f str) (toMax k)
+{-# INLINE mapMaybeM #-}
+
+mapMaybeListA :: Applicative f => (a -> f (Maybe b)) -> [a] -> f [b]
+mapMaybeListA f = fmap catMaybes . Traversable.traverse f
+{-# INLINE mapMaybeListA #-}
+
+mapMaybeStreamM :: Monad m => (a -> m (Maybe b)) -> S.Stream m a -> S.Stream m b
+mapMaybeStreamM f (S.Stream step t) = S.Stream step' t
+  where
+    step' s = do
+      r <- step s
+      case r of
+        S.Yield x s' -> do
+          b <- f x
+          return $
+            case b of
+              Nothing -> S.Skip s'
+              Just b' -> S.Yield b' s'
+        S.Skip s' -> return $ S.Skip s'
+        S.Done -> return S.Done
+    {-# INLINE step' #-}
+{-# INLINE mapMaybeStreamM #-}
+
+filter :: Monad m => (a -> Bool) -> Steps m a -> Steps m a
+filter f (Steps str k) = Steps (S.filter f str) (toMax k)
+{-# INLINE filter #-}
+
+
+filterA :: (Monad m, Applicative f) => (e -> f Bool) -> Steps Id e -> f (Steps m e)
+filterA f (Steps str k) = (`Steps` toMax k) <$> liftListA (M.filterM f) str
+{-# INLINE filterA #-}
+
+filterM :: Monad m => (e -> m Bool) -> Steps m e -> Steps m e
+filterM f (Steps str k) = Steps (S.filterM f str) (toMax k)
+{-# INLINE filterM #-}
+
+take :: Monad m => Int -> Steps m a -> Steps m a
+take n (Steps str _) = Steps (S.take n str) (Max n)
+{-# INLINE take #-}
+
+drop :: Monad m => Int -> Steps m a -> Steps m a
+drop n (Steps str k) = Steps (S.drop n str) (k `clampedSubtract` Exact n)
+{-# INLINE drop #-}
+
+slice :: Monad m => Int -> Int -> Steps m a -> Steps m a
+slice i k (Steps str _) = Steps (S.slice i k str) (Max k)
+{-# INLINE slice #-}
+
+unfoldr :: Monad m => (s -> Maybe (e, s)) -> s -> Steps m e
+unfoldr f e0 = Steps (S.unfoldr f e0) Unknown
+{-# INLINE unfoldr #-}
+
+unfoldrN :: Monad m => Sz1 -> (s -> Maybe (e, s)) -> s -> Steps m e
+unfoldrN n f e0 = Steps (S.unfoldrN (unSz n) f e0) (Max (unSz n))
+{-# INLINE unfoldrN #-}
+
+toList :: Steps Id e -> [e]
+toList (Steps str _) = unId (S.toList str)
+{-# INLINE toList #-}
+
+fromList :: Monad m => [e] -> Steps m e
+fromList = (`Steps` Unknown) . S.fromList
+{-# INLINE fromList #-}
+
+fromListN :: Monad m => Int -> [e] -> Steps m e
+fromListN n  = (`Steps` Exact n) . S.fromListN n
+{-# INLINE fromListN #-}
+
+liftListA :: (Monad m, Functor f) => ([a] -> f [b]) -> S.Stream Id a -> f (S.Stream m b)
+liftListA f str = S.fromList <$> f (unId (S.toList str))
+{-# INLINE liftListA #-}
diff --git a/src/Data/Massiv/Array/Mutable.hs b/src/Data/Massiv/Array/Mutable.hs
--- a/src/Data/Massiv/Array/Mutable.hs
+++ b/src/Data/Massiv/Array/Mutable.hs
@@ -258,8 +258,9 @@
   -> m (MArray (PrimState m) r ix e)
 loadArrayS arr = do
   marr <- newMaybeInitialized arr
-  loadArrayM trivialScheduler_ arr (unsafeLinearWrite marr)
-  pure marr
+  unsafeLoadIntoS marr arr
+  -- loadArrayM trivialScheduler_ arr (unsafeLinearWrite marr)
+  -- pure marr
 {-# INLINE loadArrayS #-}
 
 
@@ -273,8 +274,9 @@
 loadArray arr =
   liftIO $ do
     marr <- newMaybeInitialized arr
-    withScheduler_ (getComp arr) $ \scheduler -> loadArrayM scheduler arr (unsafeLinearWrite marr)
-    pure marr
+    unsafeLoadInto marr arr
+    -- withScheduler_ (getComp arr) $ \scheduler -> loadArrayM scheduler arr (unsafeLinearWrite marr)
+    -- pure marr
 {-# INLINE loadArray #-}
 
 
diff --git a/src/Data/Massiv/Array/Ops/Construct.hs b/src/Data/Massiv/Array/Ops/Construct.hs
--- a/src/Data/Massiv/Array/Ops/Construct.hs
+++ b/src/Data/Massiv/Array/Ops/Construct.hs
@@ -30,6 +30,8 @@
   , iterateN
   , iiterateN
     -- *** Unfolding
+  , unfoldr
+  , unfoldrN
   , unfoldlS_
   , iunfoldlS_
   , unfoldrS_
@@ -67,6 +69,7 @@
 import Control.Monad.ST
 import Data.Massiv.Array.Delayed.Pull
 import Data.Massiv.Array.Delayed.Push
+import Data.Massiv.Array.Delayed.Stream (unfoldr, unfoldrN)
 import Data.Massiv.Array.Mutable
 import Data.Massiv.Core.Common
 import Prelude as P hiding (enumFromTo, replicate)
diff --git a/src/Data/Massiv/Array/Ops/Map.hs b/src/Data/Massiv/Array/Ops/Map.hs
--- a/src/Data/Massiv/Array/Ops/Map.hs
+++ b/src/Data/Massiv/Array/Ops/Map.hs
@@ -272,7 +272,7 @@
 -- @since 0.2.6
 --
 traverseA ::
-     (Source r' ix a, Mutable r ix e, Applicative f)
+     forall r ix e r' a f . (Source r' ix a, Mutable r ix e, Applicative f)
   => (a -> f e)
   -> Array r' ix a
   -> f (Array r ix e)
@@ -283,7 +283,7 @@
 --
 -- @since 0.3.0
 --
-traverseA_ :: (Source r ix a, Applicative f) => (a -> f e) -> Array r ix a -> f ()
+traverseA_ :: forall r ix e a f . (Source r ix e, Applicative f) => (e -> f a) -> Array r ix e -> f ()
 traverseA_ f arr = loopA_ 0 (< totalElem (size arr)) (+ 1) (f . unsafeLinearIndex arr)
 {-# INLINE traverseA_ #-}
 
@@ -292,7 +292,9 @@
 -- @since 0.3.0
 --
 sequenceA ::
-     (Source r' ix (f e), Mutable r ix e, Applicative f) => Array r' ix (f e) -> f (Array r ix e)
+     forall r ix e r' f. (Source r' ix (f e), Mutable r ix e, Applicative f)
+  => Array r' ix (f e)
+  -> f (Array r ix e)
 sequenceA = traverseA id
 {-# INLINE sequenceA #-}
 
@@ -300,7 +302,7 @@
 --
 -- @since 0.3.0
 --
-sequenceA_ :: (Source r ix (f e), Applicative f) => Array r ix (f e) -> f ()
+sequenceA_ :: forall r ix e f . (Source r ix (f e), Applicative f) => Array r ix (f e) -> f ()
 sequenceA_ = traverseA_ id
 {-# INLINE sequenceA_ #-}
 
@@ -310,7 +312,7 @@
 -- @since 0.2.6
 --
 itraverseA ::
-     (Source r' ix a, Mutable r ix e, Applicative f)
+     forall r ix e r' a f . (Source r' ix a, Mutable r ix e, Applicative f)
   => (ix -> a -> f e)
   -> Array r' ix a
   -> f (Array r ix e)
@@ -323,7 +325,11 @@
 --
 -- @since 0.2.6
 --
-itraverseA_ :: (Source r ix a, Applicative f) => (ix -> a -> f e) -> Array r ix a -> f ()
+itraverseA_ ::
+     forall r ix e a f. (Source r ix a, Applicative f)
+  => (ix -> a -> f e)
+  -> Array r ix a
+  -> f ()
 itraverseA_ f arr =
   loopA_ 0 (< totalElem sz) (+ 1) (\ !i -> f (fromLinearIndex sz i) (unsafeLinearIndex arr i))
   where
@@ -344,6 +350,7 @@
   -> f (Array r ix b)
 traverseAR _ = traverseA
 {-# INLINE traverseAR #-}
+{-# DEPRECATED traverseAR "In favor of `traverseA`" #-}
 
 -- | Same as `itraverseA`, except with ability to specify representation.
 --
@@ -357,6 +364,7 @@
   -> f (Array r ix b)
 itraverseAR _ = itraverseA
 {-# INLINE itraverseAR #-}
+{-# DEPRECATED itraverseAR "In favor of `itraverseA`" #-}
 
 
 
@@ -391,7 +399,7 @@
 {-# INLINE itraversePrim #-}
 
 
--- | Same as `traverseP`, but with ability to specify the desired representation.
+-- | Same as `traversePrim`, but with ability to specify the desired representation.
 --
 -- @since 0.3.0
 --
@@ -403,8 +411,9 @@
   -> m (Array r ix b)
 traversePrimR _ = traversePrim
 {-# INLINE traversePrimR #-}
+{-# DEPRECATED traversePrimR "In favor of `traversePrim`" #-}
 
--- | Same as `itraverseP`, but with ability to specify the desired representation.
+-- | Same as `itraversePrim`, but with ability to specify the desired representation.
 --
 -- @since 0.3.0
 --
@@ -416,6 +425,7 @@
   -> m (Array r ix b)
 itraversePrimR _ = itraversePrim
 {-# INLINE itraversePrimR #-}
+{-# DEPRECATED itraversePrimR "In favor of `itraversePrim`" #-}
 
 
 --------------------------------------------------------------------------------
diff --git a/src/Data/Massiv/Array/Ops/Transform.hs b/src/Data/Massiv/Array/Ops/Transform.hs
--- a/src/Data/Massiv/Array/Ops/Transform.hs
+++ b/src/Data/Massiv/Array/Ops/Transform.hs
@@ -17,6 +17,10 @@
     transpose
   , transposeInner
   , transposeOuter
+  -- ** Reverse
+  , reverse
+  , reverse'
+  , reverseM
   -- ** Backpermute
   , backpermuteM
   , backpermute'
@@ -44,6 +48,8 @@
   , splitAtM
   , splitAt'
   , splitExtractM
+  , takeS
+  , dropS
   -- ** Upsample/Downsample
   , upsample
   , downsample
@@ -63,12 +69,13 @@
 import qualified Data.List as L (uncons)
 import Data.Massiv.Array.Delayed.Pull
 import Data.Massiv.Array.Delayed.Push
+import Data.Massiv.Array.Delayed.Stream
 import Data.Massiv.Array.Mutable
 import Data.Massiv.Array.Ops.Construct
 import Data.Massiv.Array.Ops.Map
 import Data.Massiv.Core.Common
 import Data.Massiv.Core.Index.Internal (Sz(SafeSz))
-import Prelude as P hiding (concat, splitAt, traverse, mapM_)
+import Prelude as P hiding (concat, splitAt, traverse, mapM_, reverse, take, drop)
 
 
 -- | Extract a sub-array from within a larger source array. Array that is being extracted must be
@@ -280,6 +287,58 @@
     !newsz = Sz (transOuter (unSz (size arr)))
 {-# INLINE [1] transposeOuter #-}
 
+-- | Reverse an array along some dimension. Dimension supplied is checked at compile time.
+--
+-- ==== __Example__
+--
+-- >>> import Data.Massiv.Array as A
+-- >>> arr = makeArrayLinear Seq (Sz2 4 5) (+10) :: Array D Ix2 Int
+-- >>> arr
+-- Array D Seq (Sz (4 :. 5))
+--   [ [ 10, 11, 12, 13, 14 ]
+--   , [ 15, 16, 17, 18, 19 ]
+--   , [ 20, 21, 22, 23, 24 ]
+--   , [ 25, 26, 27, 28, 29 ]
+--   ]
+-- >>> A.reverse Dim1 arr
+-- Array D Seq (Sz (4 :. 5))
+--   [ [ 14, 13, 12, 11, 10 ]
+--   , [ 19, 18, 17, 16, 15 ]
+--   , [ 24, 23, 22, 21, 20 ]
+--   , [ 29, 28, 27, 26, 25 ]
+--   ]
+-- >>> A.reverse Dim2 arr
+-- Array D Seq (Sz (4 :. 5))
+--   [ [ 25, 26, 27, 28, 29 ]
+--   , [ 20, 21, 22, 23, 24 ]
+--   , [ 15, 16, 17, 18, 19 ]
+--   , [ 10, 11, 12, 13, 14 ]
+--   ]
+--
+-- @since 0.4.1
+reverse :: (IsIndexDimension ix n, Source r ix e) => Dimension n -> Array r ix e -> Array D ix e
+reverse dim = reverse' (fromDimension dim)
+{-# INLINE reverse #-}
+
+-- | Similarly to `reverse`, flip an array along a particular dimension, but throws
+-- `IndexDimensionException` for an incorrect dimension.
+--
+-- @since 0.4.1
+reverseM :: (MonadThrow m, Source r ix e) => Dim -> Array r ix e -> m (Array D ix e)
+reverseM dim arr = do
+  let sz = size arr
+  k <- getDimM (unSz sz) dim
+  pure $ makeArray (getComp arr) sz $ \ ix ->
+    unsafeIndex arr (snd $ modifyDim' ix dim (\i -> k - i - 1))
+{-# INLINE reverseM #-}
+
+-- | Reverse an array along some dimension. Same as `reverseM`, but throws the
+-- `IndexDimensionException` from pure code.
+--
+-- @since 0.4.1
+reverse' :: Source r ix e => Dim -> Array r ix e -> Array D ix e
+reverse' dim = either throw id . reverseM dim
+{-# INLINE reverse' #-}
 
 -- | Rearrange elements of an array into a new one by using a function that maps indices of the
 -- newly created one into the old one. This function can throw `IndexOutOfBoundsException`.
diff --git a/src/Data/Massiv/Core.hs b/src/Data/Massiv/Core.hs
--- a/src/Data/Massiv/Core.hs
+++ b/src/Data/Massiv/Core.hs
@@ -11,6 +11,7 @@
   , Elt
   , Construct
   , Load(R, loadArrayM, defaultElement)
+  , Stream(..)
   , Source
   , Resize
   , Extract
diff --git a/src/Data/Massiv/Core/Common.hs b/src/Data/Massiv/Core/Common.hs
--- a/src/Data/Massiv/Core/Common.hs
+++ b/src/Data/Massiv/Core/Common.hs
@@ -16,6 +16,8 @@
 module Data.Massiv.Core.Common
   ( Array
   , Elt
+  , Steps(..)
+  , Stream(..)
   , Construct(..)
   , Source(..)
   , Load(..)
@@ -49,6 +51,7 @@
   , elemsCount
   , isEmpty
   , Sz(SafeSz)
+  , Size(..)
   -- * Indexing
   , (!?)
   , index
@@ -72,6 +75,7 @@
   , ShapeException(..)
   , module Data.Massiv.Core.Exception
   , Proxy(..)
+  , Id(..)
   -- * Stateful Monads
   , MonadUnliftIO
   , MonadIO(liftIO)
@@ -86,11 +90,14 @@
 import Control.Monad.IO.Unlift (MonadIO(liftIO), MonadUnliftIO)
 import Control.Monad.Primitive
 import Control.Scheduler (Comp(..), Scheduler, WorkerStates, numWorkers,
-                          scheduleWork, scheduleWork_)
+                          scheduleWork, scheduleWork_, withScheduler_, trivialScheduler_)
 import Data.Massiv.Core.Exception
 import Data.Massiv.Core.Index
 import Data.Massiv.Core.Index.Internal (Sz(SafeSz))
 import Data.Typeable
+import Data.Vector.Fusion.Bundle.Size
+import qualified Data.Vector.Fusion.Stream.Monadic as S
+import Data.Vector.Fusion.Util
 
 #include "massiv.h"
 
@@ -106,6 +113,21 @@
 
 type family NestedStruct r ix e :: *
 
+
+
+class Stream r ix e where
+  toStream :: Array r ix e -> Steps Id e
+
+data Steps m e = Steps
+  { stepsStream :: S.Stream m e
+  , stepsSize   :: Size
+  }
+
+instance Monad m => Functor (Steps m) where
+  fmap f s = s { stepsStream = S.map f (stepsStream s) }
+  {-# INLINE fmap #-}
+
+
 -- | Array types that can be constructed.
 class (Typeable r, Index ix) => Construct r ix e where
   {-# MINIMAL setComp,(makeArray|makeArrayLinear) #-}
@@ -227,6 +249,7 @@
   -- @since 0.1.0
   size :: Array r ix e -> Sz ix
 
+
   -- | Load an array into memory.
   --
   -- @since 0.3.0
@@ -240,6 +263,43 @@
   defaultElement :: Array r ix e -> Maybe e
   defaultElement _ = Nothing
   {-# INLINE defaultElement #-}
+
+  -- | /O(1)/ - Get the possible maximum size of an immutabe array. If the lookup of size
+  -- in constant time is not possible, `Nothing` should be returned. This value will be
+  -- used as the initial size of the mutable array in which loading will happen.
+  --
+  -- @since 0.4.1
+  maxSize :: Array r ix e -> Maybe (Sz ix)
+  maxSize = Just . size
+  {-# INLINE maxSize #-}
+
+  -- | Load into a supplied mutable array sequentially. Returned array does npt have to be
+  -- the same
+  --
+  -- @since 0.4.1
+  unsafeLoadIntoS ::
+       (Mutable r' ix e, PrimMonad m)
+    => MArray (PrimState m) r' ix e
+    -> Array r ix e
+    -> m (MArray (PrimState m) r' ix e)
+  unsafeLoadIntoS marr arr = do
+    loadArrayM trivialScheduler_ arr (unsafeLinearWrite marr)
+    pure marr
+  {-# INLINE unsafeLoadIntoS #-}
+
+  -- | Same as `unsafeLoadIntoS`, but with respect of computation startegy.
+  --
+  -- @since 0.4.1
+  unsafeLoadInto ::
+       (Mutable r' ix e, MonadIO m)
+    => MArray RealWorld r' ix e
+    -> Array r ix e
+    -> m (MArray RealWorld r' ix e)
+  unsafeLoadInto marr arr = do
+    liftIO $ withScheduler_ (getComp arr) $ \scheduler ->
+      loadArrayM scheduler arr (unsafeLinearWrite marr)
+    pure marr
+  {-# INLINE unsafeLoadInto #-}
 
 
 class Load r ix e => StrideLoad r ix e where
diff --git a/src/Data/Massiv/Core/Index.hs b/src/Data/Massiv/Core/Index.hs
--- a/src/Data/Massiv/Core/Index.hs
+++ b/src/Data/Massiv/Core/Index.hs
@@ -65,6 +65,7 @@
   , initDim
   , getDim'
   , setDim'
+  , modifyDim'
   , dropDimM
   , dropDim'
   , pullOutDim'
@@ -72,6 +73,7 @@
   , fromDimension
   , getDimension
   , setDimension
+  , modifyDimension
   , dropDimension
   , pullOutDimension
   , insertDimension
@@ -296,6 +298,19 @@
 getDim' ix = either throw id . getDimM ix
 {-# INLINE [1] getDim' #-}
 
+-- | Update the value of a specific dimension within the index. Throws `IndexException`. See
+-- `modifyDimM` for a safer version and `modifyDimension` for a type safe version.
+--
+-- ==== __Examples__
+--
+-- >>> modifyDim' (2 :> 3 :> 4 :. 5) 2 (+ 10)
+-- (4,2 :> 3 :> 14 :. 5)
+--
+-- @since 0.4.1
+modifyDim' :: Index ix => ix -> Dim -> (Int -> Int) -> (Int, ix)
+modifyDim' ix dim = either throw id . modifyDimM ix dim
+{-# INLINE [1] modifyDim' #-}
+
 -- | Remove a dimension from the index.
 --
 -- ==== __Examples__
@@ -379,6 +394,18 @@
 setDimension :: IsIndexDimension ix n => ix -> Dimension n -> Int -> ix
 setDimension ix = setDim' ix . fromDimension
 {-# INLINE [1] setDimension #-}
+
+-- | Type safe way to set value of index at a particular dimension.
+--
+-- ==== __Examples__
+--
+-- >>> modifyDimension (2 :> 3 :> 4 :. 5) Dim3 (+ 2)
+-- (3,2 :> 5 :> 4 :. 5)
+--
+-- @since 0.4.1
+modifyDimension :: IsIndexDimension ix n => ix -> Dimension n -> (Int -> Int) -> (Int, ix)
+modifyDimension ix = modifyDim' ix . fromDimension
+{-# INLINE [1] modifyDimension #-}
 
 -- | Type safe way to extract value of index at a particular dimension.
 --
diff --git a/src/Data/Massiv/Core/Index/Internal.hs b/src/Data/Massiv/Core/Index/Internal.hs
--- a/src/Data/Massiv/Core/Index/Internal.hs
+++ b/src/Data/Massiv/Core/Index/Internal.hs
@@ -398,11 +398,30 @@
   insertDimM :: MonadThrow m => Lower ix -> Dim -> Int -> m ix
 
   -- | Extract the value index has at specified dimension.
+  --
+  -- @since 0.3.0
   getDimM :: MonadThrow m => ix -> Dim -> m Int
+  getDimM ix dim = fst <$> modifyDimM ix dim id
+  {-# INLINE [1] getDimM #-}
 
   -- | Set the value for an index at specified dimension.
+  --
+  -- @since 0.3.0
   setDimM :: MonadThrow m => ix -> Dim -> Int -> m ix
+  setDimM ix dim i = snd <$> modifyDimM ix dim (const i)
+  {-# INLINE [1] setDimM #-}
 
+  -- | Update the value for an index at specified dimension and return the old value as
+  -- well as the updated index.
+  --
+  -- @since 0.4.1
+  modifyDimM :: MonadThrow m => ix -> Dim -> (Int -> Int) -> m (Int, ix)
+  modifyDimM ix dim f = do
+    i <- getDimM ix dim
+    ix' <- setDimM ix dim (f i)
+    pure (i, ix')
+  {-# INLINE [1] modifyDimM #-}
+
   -- | Lift an `Int` to any index by replicating the value as many times as there are dimensions.
   --
   -- @since 0.1.0
@@ -615,13 +634,16 @@
   {-# INLINE [1] snocDim #-}
   unsnocDim i = (Ix0, i)
   {-# INLINE [1] unsnocDim #-}
-  getDimM i  1 = pure i
+  getDimM ix 1 = pure ix
   getDimM ix d = throwM $ IndexDimensionException ix d
   {-# INLINE [1] getDimM #-}
-  setDimM _  1 i = pure i
-  setDimM ix d _ = throwM $ IndexDimensionException ix d
+  setDimM _  1 ix = pure ix
+  setDimM ix d _  = throwM $ IndexDimensionException ix d
   {-# INLINE [1] setDimM #-}
-  pullOutDimM i  1 = pure (i, Ix0)
+  modifyDimM ix 1 f = pure (ix, f ix)
+  modifyDimM ix d _ = throwM $ IndexDimensionException ix d
+  {-# INLINE [1] modifyDimM #-}
+  pullOutDimM ix 1 = pure (ix, Ix0)
   pullOutDimM ix d = throwM $ IndexDimensionException ix d
   {-# INLINE [1] pullOutDimM #-}
   insertDimM Ix0 1 i = pure i
diff --git a/src/Data/Massiv/Core/Index/Tuple.hs b/src/Data/Massiv/Core/Index/Tuple.hs
--- a/src/Data/Massiv/Core/Index/Tuple.hs
+++ b/src/Data/Massiv/Core/Index/Tuple.hs
@@ -186,6 +186,10 @@
   setDimM (i2, _) 1 i1 = pure (i2, i1)
   setDimM ix      d _  = throwM $ IndexDimensionException ix d
   {-# INLINE [1] setDimM #-}
+  modifyDimM (i2, i1) 2 f = pure (i2, (f i2,   i1))
+  modifyDimM (i2, i1) 1 f = pure (i1, (  i2, f i1))
+  modifyDimM ix       d _  = throwM $ IndexDimensionException ix d
+  {-# INLINE [1] modifyDimM #-}
   pullOutDimM (i2, i1) 2 = pure (i2, i1)
   pullOutDimM (i2, i1) 1 = pure (i1, i2)
   pullOutDimM ix       d = throwM $ IndexDimensionException ix d
@@ -226,6 +230,11 @@
   setDimM (i3, i2,  _) 1 i1 = pure (i3, i2, i1)
   setDimM ix           d _  = throwM $ IndexDimensionException ix d
   {-# INLINE [1] setDimM #-}
+  modifyDimM (i3, i2, i1) 3 f = pure (i3, (f i3,   i2,   i1))
+  modifyDimM (i3, i2, i1) 2 f = pure (i2, (  i3, f i2,   i1))
+  modifyDimM (i3, i2, i1) 1 f = pure (i1, (  i3,   i2, f i1))
+  modifyDimM ix           d _  = throwM $ IndexDimensionException ix d
+  {-# INLINE [1] modifyDimM #-}
   pullOutDimM (i3, i2, i1) 3 = pure (i3, (i2, i1))
   pullOutDimM (i3, i2, i1) 2 = pure (i2, (i3, i1))
   pullOutDimM (i3, i2, i1) 1 = pure (i1, (i3, i2))
@@ -267,6 +276,12 @@
   setDimM (i4, i3, i2,  _) 1 i1 = pure (i4, i3, i2, i1)
   setDimM ix               d  _ = throwM $ IndexDimensionException ix d
   {-# INLINE [1] setDimM #-}
+  modifyDimM (i4, i3, i2, i1) 4 f = pure (i4, (f i4,   i3,   i2,   i1))
+  modifyDimM (i4, i3, i2, i1) 3 f = pure (i3, (  i4, f i3,   i2,   i1))
+  modifyDimM (i4, i3, i2, i1) 2 f = pure (i2, (  i4,   i3, f i2,   i1))
+  modifyDimM (i4, i3, i2, i1) 1 f = pure (i1, (  i4,   i3,   i2, f i1))
+  modifyDimM ix               d _ = throwM $ IndexDimensionException ix d
+  {-# INLINE [1] modifyDimM #-}
   pullOutDimM (i4, i3, i2, i1) 4 = pure (i4, (i3, i2, i1))
   pullOutDimM (i4, i3, i2, i1) 3 = pure (i3, (i4, i2, i1))
   pullOutDimM (i4, i3, i2, i1) 2 = pure (i2, (i4, i3, i1))
@@ -313,6 +328,13 @@
   setDimM (i5, i4, i3, i2,  _) 1 i1 = pure (i5, i4, i3, i2, i1)
   setDimM ix                   d  _ = throwM $ IndexDimensionException ix d
   {-# INLINE [1] setDimM #-}
+  modifyDimM (i5, i4, i3, i2, i1) 5 f = pure (i5, (f i5,   i4,   i3,   i2,   i1))
+  modifyDimM (i5, i4, i3, i2, i1) 4 f = pure (i4, (  i5, f i4,   i3,   i2,   i1))
+  modifyDimM (i5, i4, i3, i2, i1) 3 f = pure (i3, (  i5,   i4, f i3,   i2,   i1))
+  modifyDimM (i5, i4, i3, i2, i1) 2 f = pure (i2, (  i5,   i4,   i3, f i2,   i1))
+  modifyDimM (i5, i4, i3, i2, i1) 1 f = pure (i1, (  i5,   i4,   i3,   i2, f i1))
+  modifyDimM ix                   d _ = throwM $ IndexDimensionException ix d
+  {-# INLINE [1] modifyDimM #-}
   pullOutDimM (i5, i4, i3, i2, i1) 5 = pure (i5, (i4, i3, i2, i1))
   pullOutDimM (i5, i4, i3, i2, i1) 4 = pure (i4, (i5, i3, i2, i1))
   pullOutDimM (i5, i4, i3, i2, i1) 3 = pure (i3, (i5, i4, i2, i1))
diff --git a/src/Data/Massiv/Core/List.hs b/src/Data/Massiv/Core/List.hs
--- a/src/Data/Massiv/Core/List.hs
+++ b/src/Data/Massiv/Core/List.hs
@@ -32,6 +32,7 @@
 import Data.Coerce
 import Data.Foldable (foldr')
 import qualified Data.List as L
+import qualified Data.Massiv.Array.Manifest.Vector.Stream as S
 import Data.Massiv.Core.Common
 import Data.Typeable
 import GHC.Exts
@@ -48,6 +49,14 @@
 newtype instance Array LN ix e = List { unList :: [Elt LN ix e] }
 
 
+instance Construct LN Ix1 e where
+  setComp _ = id
+  {-# INLINE setComp #-}
+  makeArray _ (Sz n) f = coerce (fmap f [0 .. n - 1])
+  {-# INLINE makeArray #-}
+  makeArrayLinear _ (Sz n) f = coerce (fmap f [0 .. n - 1])
+  {-# INLINE makeArrayLinear #-}
+
 instance {-# OVERLAPPING #-} Nested LN Ix1 e where
   fromNested = coerce
   {-# INLINE fromNested #-}
@@ -368,3 +377,12 @@
           Just (x, _) | n == i -> x
           Just (_, xs) -> go (n + 1) xs
   {-# INLINE unsafeOuterSlice #-}
+
+
+instance Stream LN Ix1 e where
+  toStream = S.fromList . coerce
+  {-# INLINE toStream #-}
+
+instance Ragged L ix e => Stream L ix e where
+  toStream = S.fromList . coerce . lData . flattenRagged
+  {-# INLINE toStream #-}
