{-# LANGUAGE BangPatterns #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MonoLocalBinds #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ScopedTypeVariables #-} -- | -- Module : Data.Massiv.Array.Ops.Map -- Copyright : (c) Alexey Kuleshevich 2018-2022 -- License : BSD3 -- Maintainer : Alexey Kuleshevich -- Stability : experimental -- Portability : non-portable module Data.Massiv.Array.Ops.Map ( map, imap, -- ** Traversing -- *** Applicative traverseA, traverseA_, itraverseA, itraverseA_, sequenceA, sequenceA_, -- *** PrimMonad traversePrim, itraversePrim, -- ** Monadic mapping -- *** Sequential mapM, forM, imapM, iforM, mapM_, forM_, imapM_, iforM_, -- *** Parallelizable mapIO, mapWS, mapIO_, imapIO, imapWS, imapIO_, forIO, forWS, forIO_, iforIO, iforWS, iforIO_, imapSchedulerM_, iforSchedulerM_, iterArrayLinearM_, iterArrayLinearWithSetM_, iterArrayLinearWithStrideM_, -- ** Zipping zip, zip3, zip4, unzip, unzip3, unzip4, zipWith, zipWith3, zipWith4, izipWith, izipWith3, izipWith4, -- *** Applicative zipWithA, izipWithA, zipWith3A, izipWith3A, ) where import Control.Monad (void) import Control.Monad.Primitive import Control.Scheduler import Data.Coerce import Data.Massiv.Array.Delayed.Pull import Data.Massiv.Array.Manifest.List import Data.Massiv.Array.Mutable import Data.Massiv.Array.Ops.Construct (makeArrayA, makeArrayLinearA) import Data.Massiv.Core.Common import Data.Traversable (traverse) import Prelude hiding ( map, mapM, mapM_, sequenceA, traverse, unzip, unzip3, zip, zip3, zipWith, zipWith3, ) -------------------------------------------------------------------------------- -- map ------------------------------------------------------------------------- -------------------------------------------------------------------------------- -- | Map a function over an array -- -- @since 0.1.0 map :: (Index ix, Source r e') => (e' -> e) -> Array r ix e' -> Array D ix e map f = fmap f . delay {-# INLINE map #-} -------------------------------------------------------------------------------- -- zip ------------------------------------------------------------------------- -------------------------------------------------------------------------------- -- | Zip two arrays -- -- @since 0.1.0 zip :: (Index ix, Source r1 e1, Source r2 e2) => Array r1 ix e1 -> Array r2 ix e2 -> Array D ix (e1, e2) zip = zipWith (,) {-# INLINE zip #-} -- | Zip three arrays -- -- @since 0.1.0 zip3 :: (Index ix, Source r1 e1, Source r2 e2, Source r3 e3) => Array r1 ix e1 -> Array r2 ix e2 -> Array r3 ix e3 -> Array D ix (e1, e2, e3) zip3 = zipWith3 (,,) {-# INLINE zip3 #-} -- | Zip four arrays -- -- @since 0.5.4 zip4 :: (Index ix, Source r1 e1, Source r2 e2, Source r3 e3, Source r4 e4) => Array r1 ix e1 -> Array r2 ix e2 -> Array r3 ix e3 -> Array r4 ix e4 -> Array D ix (e1, e2, e3, e4) zip4 = zipWith4 (,,,) {-# INLINE zip4 #-} -- | Unzip two arrays -- -- @since 0.1.0 unzip :: (Index ix, Source r (e1, e2)) => Array r ix (e1, e2) -> (Array D ix e1, Array D ix e2) unzip arr = (map fst arr, map snd arr) {-# INLINE unzip #-} -- | Unzip three arrays -- -- @since 0.1.0 unzip3 :: (Index ix, Source r (e1, e2, e3)) => Array r ix (e1, e2, e3) -> (Array D ix e1, Array D ix e2, Array D ix e3) unzip3 arr = (map (\(e, _, _) -> e) arr, map (\(_, e, _) -> e) arr, map (\(_, _, e) -> e) arr) {-# INLINE unzip3 #-} -- | Unzip four arrays -- -- @since 0.5.4 unzip4 :: (Index ix, Source r (e1, e2, e3, e4)) => Array r ix (e1, e2, e3, e4) -> (Array D ix e1, Array D ix e2, Array D ix e3, Array D ix e4) unzip4 arr = ( map (\(e, _, _, _) -> e) arr , map (\(_, e, _, _) -> e) arr , map (\(_, _, e, _) -> e) arr , map (\(_, _, _, e) -> e) arr ) {-# INLINE unzip4 #-} -------------------------------------------------------------------------------- -- zipWith --------------------------------------------------------------------- -------------------------------------------------------------------------------- -- | Zip two arrays with a function. Resulting array will be an intersection of -- source arrays in case their dimensions do not match. zipWith :: (Index ix, Source r1 e1, Source r2 e2) => (e1 -> e2 -> e) -> Array r1 ix e1 -> Array r2 ix e2 -> Array D ix e zipWith f arr1 arr2 = DArray comp sz prefIndex where sz = SafeSz (liftIndex2 min (coerce (size arr1)) (coerce (size arr2))) comp = getComp arr1 <> getComp arr2 prefIndex = PrefIndex (\ix -> f (unsafeIndex arr1 ix) (unsafeIndex arr2 ix)) -- Somehow checking for size equality destroys performance -- | PrefIndexLinear gi1 <- unsafePrefIndex arr1, -- PrefIndexLinear gi2 <- unsafePrefIndex arr2, -- size arr1 == size arr2 = -- PrefIndexLinear (\i -> f (gi1 i) (gi2 i)) -- | otherwise = PrefIndex (\ix -> f (unsafeIndex arr1 ix) (unsafeIndex arr2 ix)) {-# INLINE zipWith #-} -- | Just like `zipWith`, except with an index aware function. izipWith :: (Index ix, Source r1 e1, Source r2 e2) => (ix -> e1 -> e2 -> e) -> Array r1 ix e1 -> Array r2 ix e2 -> Array D ix e izipWith f arr1 arr2 = DArray (getComp arr1 <> getComp arr2) (SafeSz (liftIndex2 min (coerce (size arr1)) (coerce (size arr2)))) (PrefIndex (\ix -> f ix (unsafeIndex arr1 ix) (unsafeIndex arr2 ix))) {-# INLINE izipWith #-} -- | Just like `zipWith`, except zip three arrays with a function. zipWith3 :: (Index ix, Source r1 e1, Source r2 e2, Source r3 e3) => (e1 -> e2 -> e3 -> e) -> Array r1 ix e1 -> Array r2 ix e2 -> Array r3 ix e3 -> Array D ix e zipWith3 f arr1 arr2 arr3 = izipWith3 (\_ e1 e2 e3 -> f e1 e2 e3) arr1 arr2 arr3 -- See note on zipWith -- | sz1 == size arr2 && sz1 == size arr3 -- , PrefIndexLinear gi1 <- unsafePrefIndex arr1 -- , PrefIndexLinear gi2 <- unsafePrefIndex arr2 -- , PrefIndexLinear gi3 <- unsafePrefIndex arr3 = -- makeArrayLinear comp sz1 (\ !i -> f (gi1 i) (gi2 i) (gi3 i)) -- | otherwise = izipWith3 (\_ e1 e2 e3 -> f e1 e2 e3) arr1 arr2 arr3 -- where -- comp = getComp arr1 <> getComp arr2 <> getComp arr3 -- sz1 = size arr1 {-# INLINE zipWith3 #-} -- | Just like `zipWith3`, except with an index aware function. izipWith3 :: (Index ix, Source r1 e1, Source r2 e2, Source r3 e3) => (ix -> e1 -> e2 -> e3 -> e) -> Array r1 ix e1 -> Array r2 ix e2 -> Array r3 ix e3 -> Array D ix e izipWith3 f arr1 arr2 arr3 = DArray (getComp arr1 <> getComp arr2 <> getComp arr3) ( SafeSz ( liftIndex2 min (liftIndex2 min (coerce (size arr1)) (coerce (size arr2))) (coerce (size arr3)) ) ) (PrefIndex $ \ !ix -> f ix (unsafeIndex arr1 ix) (unsafeIndex arr2 ix) (unsafeIndex arr3 ix)) {-# INLINE izipWith3 #-} -- | Just like `zipWith`, except zip four arrays with a function. -- -- @since 0.5.4 zipWith4 :: (Index ix, Source r1 e1, Source r2 e2, Source r3 e3, Source r4 e4) => (e1 -> e2 -> e3 -> e4 -> e) -> Array r1 ix e1 -> Array r2 ix e2 -> Array r3 ix e3 -> Array r4 ix e4 -> Array D ix e zipWith4 f arr1 arr2 arr3 arr4 = izipWith4 (\_ e1 e2 e3 e4 -> f e1 e2 e3 e4) arr1 arr2 arr3 arr4 -- See note on zipWith -- | sz1 == size arr2 && sz1 == size arr3 && sz1 == size arr4 -- , PrefIndexLinear gi1 <- unsafePrefIndex arr1 -- , PrefIndexLinear gi2 <- unsafePrefIndex arr2 -- , PrefIndexLinear gi3 <- unsafePrefIndex arr3 -- , PrefIndexLinear gi4 <- unsafePrefIndex arr4 = -- makeArrayLinear comp sz1 (\ !i -> f (gi1 i) (gi2 i) (gi3 i) (gi4 i)) -- | otherwise = izipWith4 (\ _ e1 e2 e3 e4 -> f e1 e2 e3 e4) arr1 arr2 arr3 arr4 -- where -- comp = getComp arr1 <> getComp arr2 <> getComp arr3 <> getComp arr4 -- sz1 = size arr1 {-# INLINE zipWith4 #-} -- | Just like `zipWith4`, except with an index aware function. -- -- @since 0.5.4 izipWith4 :: (Index ix, Source r1 e1, Source r2 e2, Source r3 e3, Source r4 e4) => (ix -> e1 -> e2 -> e3 -> e4 -> e) -> Array r1 ix e1 -> Array r2 ix e2 -> Array r3 ix e3 -> Array r4 ix e4 -> Array D ix e izipWith4 f arr1 arr2 arr3 arr4 = makeArray (getComp arr1 <> getComp arr2 <> getComp arr3 <> getComp arr4) ( SafeSz ( liftIndex2 min ( liftIndex2 min (liftIndex2 min (coerce (size arr1)) (coerce (size arr2))) (coerce (size arr3)) ) (coerce (size arr4)) ) ) ( \ !ix -> f ix (unsafeIndex arr1 ix) (unsafeIndex arr2 ix) (unsafeIndex arr3 ix) (unsafeIndex arr4 ix) ) {-# INLINE izipWith4 #-} -- | Similar to `zipWith`, except does it sequentially and using the `Applicative`. Note that -- resulting array has Manifest representation. -- -- @since 0.3.0 zipWithA :: (Source r1 e1, Source r2 e2, Applicative f, Manifest r e, Index ix) => (e1 -> e2 -> f e) -> Array r1 ix e1 -> Array r2 ix e2 -> f (Array r ix e) zipWithA f arr1 arr2 | sz1 == size arr2 , PrefIndexLinear gi1 <- unsafePrefIndex arr1 , PrefIndexLinear gi2 <- unsafePrefIndex arr2 = setComp (getComp arr1 <> getComp arr2) <$> makeArrayLinearA sz1 (\ !i -> f (gi1 i) (gi2 i)) | otherwise = izipWithA (const f) arr1 arr2 where !sz1 = size arr1 {-# INLINE zipWithA #-} -- | Similar to `zipWith`, except does it sequentially and using the `Applicative`. Note that -- resulting array has Manifest representation. -- -- @since 0.3.0 izipWithA :: (Source r1 e1, Source r2 e2, Applicative f, Manifest r e, Index ix) => (ix -> e1 -> e2 -> f e) -> Array r1 ix e1 -> Array r2 ix e2 -> f (Array r ix e) izipWithA f arr1 arr2 = setComp (getComp arr1 <> getComp arr2) <$> makeArrayA (SafeSz (liftIndex2 min (coerce (size arr1)) (coerce (size arr2)))) (\ !ix -> f ix (unsafeIndex arr1 ix) (unsafeIndex arr2 ix)) {-# INLINE izipWithA #-} -- | Same as `zipWithA`, but for three arrays. -- -- @since 0.3.0 zipWith3A :: (Source r1 e1, Source r2 e2, Source r3 e3, Applicative f, Manifest r e, Index ix) => (e1 -> e2 -> e3 -> f e) -> Array r1 ix e1 -> Array r2 ix e2 -> Array r3 ix e3 -> f (Array r ix e) zipWith3A f = izipWith3A (const f) {-# INLINE zipWith3A #-} -- | Same as `izipWithA`, but for three arrays. -- -- @since 0.3.0 izipWith3A :: (Source r1 e1, Source r2 e2, Source r3 e3, Applicative f, Manifest r e, Index ix) => (ix -> e1 -> e2 -> e3 -> f e) -> Array r1 ix e1 -> Array r2 ix e2 -> Array r3 ix e3 -> f (Array r ix e) izipWith3A f arr1 arr2 arr3 = setComp (getComp arr1 <> getComp arr2 <> getComp arr3) <$> makeArrayA sz (\ !ix -> f ix (unsafeIndex arr1 ix) (unsafeIndex arr2 ix) (unsafeIndex arr3 ix)) where sz = SafeSz $ liftIndex2 min (liftIndex2 min (coerce (size arr1)) (coerce (size arr2))) (coerce (size arr3)) {-# INLINE izipWith3A #-} -------------------------------------------------------------------------------- -- traverse -------------------------------------------------------------------- -------------------------------------------------------------------------------- -- | Traverse with an `Applicative` action over an array sequentially. -- -- /Note/ - using `traversePrim` instead will always be significantly faster, roughly -- about 30 times faster in practice. -- -- @since 0.2.6 traverseA :: forall r ix e r' a f . (Source r' a, Manifest r e, Index ix, Applicative f) => (a -> f e) -> Array r' ix a -> f (Array r ix e) traverseA f arr = unsafeResize (size arr) . fromList (getComp arr) <$> traverse f (toList arr) {-# INLINE traverseA #-} -- | Traverse sequentially over a source array, while discarding the result. -- -- @since 0.3.0 traverseA_ :: forall r ix e a f . (Index ix, Source r e, Applicative f) => (e -> f a) -> Array r ix e -> f () traverseA_ f arr = case unsafePrefIndex arr of PrefIndex gix -> iterA_ zeroIndex (unSz sz) oneIndex (<) (f . gix) PrefIndexLinear gi -> loopA_ 0 (< totalElem sz) (+ 1) (f . gi) where sz = size arr {-# INLINE traverseA_ #-} -- | Sequence actions in a source array. -- -- @since 0.3.0 sequenceA :: forall r ix e r' f . (Source r' (f e), Manifest r e, Index ix, Applicative f) => Array r' ix (f e) -> f (Array r ix e) sequenceA = traverseA id {-# INLINE sequenceA #-} -- | Sequence actions in a source array, while discarding the result. -- -- @since 0.3.0 sequenceA_ :: forall r ix e f . (Index ix, Source r (f e), Applicative f) => Array r ix (f e) -> f () sequenceA_ = traverseA_ id {-# INLINE sequenceA_ #-} -- | Traverse with an `Applicative` index aware action over an array sequentially. -- -- @since 0.2.6 itraverseA :: forall r ix e r' a f . (Source r' a, Manifest r e, Index ix, Applicative f) => (ix -> a -> f e) -> Array r' ix a -> f (Array r ix e) itraverseA f arr = setComp (getComp arr) <$> makeArrayA (size arr) (\ !ix -> f ix (unsafeIndex arr ix)) {-# INLINE itraverseA #-} -- | Traverse with an `Applicative` index aware action over an array sequentially. -- -- @since 0.2.6 itraverseA_ :: forall r ix e a f . (Source r a, Index ix, Applicative f) => (ix -> a -> f e) -> Array r ix a -> f () itraverseA_ f arr = case unsafePrefIndex arr of PrefIndex gix -> iterA_ zeroIndex (unSz sz) oneIndex (<) (\ !ix -> f ix (gix ix)) PrefIndexLinear gi -> iterTargetA_ defRowMajor 0 sz zeroIndex oneStride $ \i ix -> f ix (gi i) where sz = size arr {-# INLINE itraverseA_ #-} -- | Traverse sequentially within `PrimMonad` over an array with an action. -- -- @since 0.3.0 traversePrim :: forall r ix b r' a m . (Source r' a, Manifest r b, Index ix, PrimMonad m) => (a -> m b) -> Array r' ix a -> m (Array r ix b) traversePrim f arr = do let sz = size arr marr <- unsafeNew sz case unsafePrefIndex arr of PrefIndex gix -> iterTargetA_ defRowMajor 0 sz zeroIndex oneStride $ \i ix -> f (gix ix) >>= unsafeLinearWrite marr i PrefIndexLinear gi -> loopA_ 0 (< totalElem sz) (+ 1) $ \i -> f (gi i) >>= unsafeLinearWrite marr i unsafeFreeze (getComp arr) marr {-# INLINE traversePrim #-} -- | Same as `traversePrim`, but traverse with index aware action. -- -- @since 0.3.0 itraversePrim :: forall r ix b r' a m . (Source r' a, Manifest r b, Index ix, PrimMonad m) => (ix -> a -> m b) -> Array r' ix a -> m (Array r ix b) itraversePrim f arr = do let sz = size arr marr <- unsafeNew sz case unsafePrefIndex arr of PrefIndex gix -> iterTargetA_ defRowMajor 0 sz zeroIndex oneStride $ \i ix -> f ix (gix ix) >>= unsafeLinearWrite marr i PrefIndexLinear gi -> iterTargetA_ defRowMajor 0 sz zeroIndex oneStride $ \i ix -> f ix (gi i) >>= unsafeLinearWrite marr i unsafeFreeze (getComp arr) marr {-# INLINE itraversePrim #-} -------------------------------------------------------------------------------- -- mapM ------------------------------------------------------------------------ -------------------------------------------------------------------------------- -- | Map a monadic action over an array sequentially. -- -- @since 0.2.6 mapM :: forall r ix b r' a m . (Source r' a, Manifest r b, Index ix, Monad m) => (a -> m b) -- ^ Mapping action -> Array r' ix a -- ^ Source array -> m (Array r ix b) mapM = traverseA {-# INLINE mapM #-} -- | Same as `mapM` except with arguments flipped. -- -- @since 0.2.6 forM :: forall r ix b r' a m . (Source r' a, Manifest r b, Index ix, Monad m) => Array r' ix a -> (a -> m b) -> m (Array r ix b) forM = flip traverseA {-# INLINE forM #-} -- | Map an index aware monadic action over an array sequentially. -- -- @since 0.2.6 imapM :: forall r ix b r' a m . (Source r' a, Manifest r b, Index ix, Monad m) => (ix -> a -> m b) -> Array r' ix a -> m (Array r ix b) imapM = itraverseA {-# INLINE imapM #-} -- | Same as `forM`, except with an index aware action. -- -- @since 0.5.1 iforM :: forall r ix b r' a m . (Source r' a, Manifest r b, Index ix, Monad m) => Array r' ix a -> (ix -> a -> m b) -> m (Array r ix b) iforM = flip itraverseA {-# INLINE iforM #-} -- | Map a monadic function over an array sequentially, while discarding the result. -- -- ==== __Examples__ -- -- >>> import Data.Massiv.Array as A -- >>> rangeStepM Par (Ix1 10) 12 60 >>= A.mapM_ print -- 10 -- 22 -- 34 -- 46 -- 58 -- -- @since 0.1.0 mapM_ :: (Source r a, Index ix, Monad m) => (a -> m b) -> Array r ix a -> m () mapM_ = traverseA_ {-# INLINE mapM_ #-} -- | Just like `mapM_`, except with flipped arguments. -- -- ==== __Examples__ -- -- Here is a common way of iterating N times using a for loop in an imperative -- language with mutation being an obvious side effect: -- -- >>> import Data.Massiv.Array as A -- >>> import Data.IORef -- >>> ref <- newIORef 0 :: IO (IORef Int) -- >>> A.forM_ (range Seq (Ix1 0) 1000) $ \ i -> modifyIORef' ref (+i) -- >>> readIORef ref -- 499500 forM_ :: (Source r a, Index ix, Monad m) => Array r ix a -> (a -> m b) -> m () forM_ = flip traverseA_ {-# INLINE forM_ #-} -- | Map a monadic index aware function over an array sequentially, while discarding the result. -- -- ==== __Examples__ -- -- >>> import Data.Massiv.Array -- >>> imapM_ (curry print) $ range Seq (Ix1 10) 15 -- (0,10) -- (1,11) -- (2,12) -- (3,13) -- (4,14) -- -- @since 0.1.0 imapM_ :: (Index ix, Source r a, Monad m) => (ix -> a -> m b) -> Array r ix a -> m () imapM_ = itraverseA_ {-# INLINE imapM_ #-} -- | Just like `imapM_`, except with flipped arguments. iforM_ :: (Source r a, Index ix, Monad m) => Array r ix a -> (ix -> a -> m b) -> m () iforM_ = flip itraverseA_ {-# INLINE iforM_ #-} -- | Map an `IO` action over an `Array`. Underlying computation strategy is respected and will be -- parallelized when requested. Unfortunately no fusion is possible and new array will be create -- upon each call. -- -- @since 0.2.6 mapIO :: forall r ix b r' a m . (Size r', Load r' ix a, Manifest r b, MonadUnliftIO m) => (a -> m b) -> Array r' ix a -> m (Array r ix b) mapIO action = imapIO (const action) {-# INLINE mapIO #-} -- | Similar to `mapIO`, but ignores the result of mapping action and does not -- create a resulting array, therefore it is faster. Use this instead of `mapIO` -- when result is irrelevant. Most importantly it will follow the iteration -- logic outlined by the supplied array. -- -- @since 0.2.6 mapIO_ :: forall r ix e a m . (Load r ix e, MonadUnliftIO m) => (e -> m a) -> Array r ix e -> m () mapIO_ action arr = withRunInIO $ \run -> withMassivScheduler_ (getComp arr) $ \scheduler -> iterArrayLinearM_ scheduler arr (\_ -> void . run . action) {-# INLINE mapIO_ #-} -- | Same as `mapIO_`, but map an index aware action instead. -- -- @since 0.2.6 imapIO_ :: forall r ix e a m . (Load r ix e, MonadUnliftIO m) => (ix -> e -> m a) -> Array r ix e -> m () imapIO_ action arr = withRunInIO $ \run -> withMassivScheduler_ (getComp arr) $ \scheduler -> let sz = outerSize arr in -- It is ok to use outerSize in context of DS and L. Former is 1-dim, -- so sz is never evaluated and for the latter outerSize has to be -- called regardless how this function is implemented. iterArrayLinearM_ scheduler arr (\i -> void . run . action (fromLinearIndex sz i)) {-# INLINE imapIO_ #-} -- | Same as `mapIO` but map an index aware action instead. Respects computation strategy. -- -- @since 0.2.6 imapIO :: forall r ix b r' a m . (Size r', Load r' ix a, Manifest r b, MonadUnliftIO m) => (ix -> a -> m b) -> Array r' ix a -> m (Array r ix b) imapIO action arr = do let sz = size arr withRunInIO $ \run -> do marr <- unsafeNew sz withMassivScheduler_ (getComp arr) $ \scheduler -> iterArrayLinearM_ scheduler arr $ \ !i e -> run (action (fromLinearIndex sz i) e) >>= unsafeLinearWrite marr i unsafeFreeze (getComp arr) marr {-# INLINE imapIO #-} -- | Same as `mapIO` but with arguments flipped. -- -- @since 0.2.6 forIO :: forall r ix b r' a m . (Size r', Load r' ix a, Manifest r b, MonadUnliftIO m) => Array r' ix a -> (a -> m b) -> m (Array r ix b) forIO = flip mapIO {-# INLINE forIO #-} -- | Same as `imapIO`, but ignores the inner computation strategy and uses -- stateful workers during computation instead. Use -- `Control.Scheduler.initWorkerStates` for the `WorkerStates` initialization. -- -- @since 0.3.4 imapWS :: forall r ix b r' a s m . (Source r' a, Manifest r b, Index ix, MonadUnliftIO m, PrimMonad m) => WorkerStates s -> (ix -> a -> s -> m b) -> Array r' ix a -> m (Array r ix b) imapWS states f arr = generateArrayWS states (size arr) (\ix s -> f ix (unsafeIndex arr ix) s) {-# INLINE imapWS #-} -- | Same as `imapWS`, but without the index. -- -- @since 0.3.4 mapWS :: forall r ix b r' a s m . (Source r' a, Manifest r b, Index ix, MonadUnliftIO m, PrimMonad m) => WorkerStates s -> (a -> s -> m b) -> Array r' ix a -> m (Array r ix b) mapWS states f = imapWS states (\_ -> f) {-# INLINE mapWS #-} -- | Same as `imapWS`, but with source array and mapping action arguments flipped. -- -- @since 0.3.4 iforWS :: forall r ix b r' a s m . (Source r' a, Manifest r b, Index ix, MonadUnliftIO m, PrimMonad m) => WorkerStates s -> Array r' ix a -> (ix -> a -> s -> m b) -> m (Array r ix b) iforWS states f arr = imapWS states arr f {-# INLINE iforWS #-} -- | Same as `iforWS`, but without the index. -- -- @since 0.3.4 forWS :: forall r ix b r' a s m . (Source r' a, Manifest r b, Index ix, MonadUnliftIO m, PrimMonad m) => WorkerStates s -> Array r' ix a -> (a -> s -> m b) -> m (Array r ix b) forWS states arr f = imapWS states (\_ -> f) arr {-# INLINE forWS #-} -- | Same as `mapIO_` but with arguments flipped. -- -- ==== __Example__ -- -- This is the same example as in `forM_`, with important difference that accumulator `ref` will be -- modified concurrently by as many threads as there are capabilities. -- -- >>> import Data.Massiv.Array -- >>> import Data.IORef -- >>> ref <- newIORef 0 :: IO (IORef Int) -- >>> forIO_ (range Par (Ix1 0) 1000) $ \ i -> atomicModifyIORef' ref (\v -> (v+i, ())) -- >>> readIORef ref -- 499500 -- -- @since 0.2.6 forIO_ :: (Load r ix e, MonadUnliftIO m) => Array r ix e -> (e -> m a) -> m () forIO_ = flip mapIO_ {-# INLINE forIO_ #-} -- | Same as `imapIO` but with arguments flipped. -- -- @since 0.2.6 iforIO :: forall r ix b r' a m . (Size r', Load r' ix a, Manifest r b, MonadUnliftIO m) => Array r' ix a -> (ix -> a -> m b) -> m (Array r ix b) iforIO = flip imapIO {-# INLINE iforIO #-} -- | Same as `imapIO_` but with arguments flipped. -- -- @since 0.2.6 iforIO_ :: forall r ix e a m . (Load r ix e, MonadUnliftIO m) => Array r ix e -> (ix -> e -> m a) -> m () iforIO_ = flip imapIO_ {-# INLINE iforIO_ #-} iterArrayLinearM_ :: forall r ix e m s . (Load r ix e, MonadPrimBase s m) => Scheduler s () -> Array r ix e -- ^ Array that is being loaded -> (Int -> e -> m ()) -- ^ Function that writes an element into target array -> m () iterArrayLinearM_ scheduler arr f = stToPrim $ iterArrayLinearST_ scheduler arr (\i -> primToPrim . f i) {-# INLINE iterArrayLinearM_ #-} iterArrayLinearWithSetM_ :: forall r ix e m s . (Load r ix e, MonadPrimBase s m) => Scheduler s () -> Array r ix e -- ^ Array that is being loaded -> (Int -> e -> m ()) -- ^ Function that writes an element into target array -> (Ix1 -> Sz1 -> e -> m ()) -- ^ Function that efficiently sets a region of an array -- to the supplied value target array -> m () iterArrayLinearWithSetM_ scheduler arr f set = stToPrim $ iterArrayLinearWithSetST_ scheduler arr (\i -> primToPrim . f i) (\i n -> primToPrim . set i n) {-# INLINE iterArrayLinearWithSetM_ #-} iterArrayLinearWithStrideM_ :: forall r ix e m s . (StrideLoad r ix e, MonadPrimBase s m) => Scheduler s () -> Stride ix -- ^ Stride to use -> Sz ix -- ^ Size of the target array affected by the stride. -> Array r ix e -- ^ Array that is being loaded -> (Int -> e -> m ()) -- ^ Function that writes an element into target array -> m () iterArrayLinearWithStrideM_ scheduler stride sz arr f = stToPrim $ iterArrayLinearWithStrideST_ scheduler stride sz arr (\i -> primToPrim . f i) {-# INLINE iterArrayLinearWithStrideM_ #-} -- iterArrayM_ :: -- Scheduler s () -- -> Array r ix e -- ^ Array that is being loaded -- -> (Int -> e -> ST s ()) -- ^ Function that writes an element into target array -- -> ST s () -- iterArrayM_ scheduler arr uWrite -- Deprecated -- | Same as `imapM_`, but will use the supplied scheduler. -- -- @since 0.3.1 imapSchedulerM_ :: (Index ix, Source r e, MonadPrimBase s m) => Scheduler s () -> (ix -> e -> m a) -> Array r ix e -> m () imapSchedulerM_ scheduler action arr = do let sz = size arr splitLinearlyWith_ scheduler (totalElem sz) (unsafeLinearIndex arr) (\i -> void . action (fromLinearIndex sz i)) {-# INLINE imapSchedulerM_ #-} -- | Same as `imapM_`, but will use the supplied scheduler. -- -- @since 0.3.1 iforSchedulerM_ :: (Index ix, Source r e, MonadPrimBase s m) => Scheduler s () -> Array r ix e -> (ix -> e -> m a) -> m () iforSchedulerM_ scheduler arr action = imapSchedulerM_ scheduler action arr {-# INLINE iforSchedulerM_ #-} -- -- | Load an array into memory. -- -- -- -- @since 0.3.0 -- loadArrayM -- :: Scheduler s () -- -> Array r ix e -- ^ Array that is being loaded -- -> (Int -> e -> ST s ()) -- ^ Function that writes an element into target array -- -> ST s () -- loadArrayM scheduler arr uWrite = -- loadArrayWithSetM scheduler arr uWrite $ \offset sz e -> -- loopM_ offset (< (offset + unSz sz)) (+1) (`uWrite` e) -- {-# INLINE loadArrayM #-} -- -- | Load an array into memory, just like `loadArrayM`. Except it also accepts a -- -- function that is potentially optimized for setting many cells in a region to the same -- -- value -- -- -- -- @since 0.5.8 -- loadArrayWithSetM -- :: Scheduler s () -- -> Array r ix e -- ^ Array that is being loaded -- -> (Ix1 -> e -> ST s ()) -- ^ Function that writes an element into target array -- -> (Ix1 -> Sz1 -> e -> ST s ()) -- ^ Function that efficiently sets a region of an array -- -- to the supplied value target array -- -> ST s () -- loadArrayWithSetM scheduler arr uWrite _ = loadArrayM scheduler arr uWrite -- {-# INLINE loadArrayWithSetM #-} -- iterArrayLinearWithStrideST -- :: Scheduler s () -- -> Stride ix -- ^ Stride to use -- -> Sz ix -- ^ Size of the target array affected by the stride. -- -> Array r ix e -- ^ Array that is being loaded -- -> (Int -> e -> ST s ()) -- ^ Function that writes an element into target array -- -> ST s ()