1 {-# OPTIONS_GHC -funbox-strict-fields #-}
2 {-# OPTIONS_GHC -fno-warn-incomplete-patterns #-}
5 -----------------------------------------------------------------------------
8 -- Copyright : (c) 2001-2002 Manuel M T Chakravarty & Gabriele Keller
9 -- License : see libraries/base/LICENSE
11 -- Maintainer : Manuel M. T. Chakravarty <chak@cse.unsw.edu.au>
12 -- Stability : internal
13 -- Portability : non-portable (GHC Extensions)
15 -- Basic implementation of Parallel Arrays.
17 -- This module has two functions: (1) It defines the interface to the
18 -- parallel array extension of the Prelude and (2) it provides a vanilla
19 -- implementation of parallel arrays that does not require to flatten the
20 -- array code. The implementation is not very optimised.
22 --- DOCU ----------------------------------------------------------------------
24 -- Language: Haskell 98 plus unboxed values and parallel arrays
26 -- The semantic difference between standard Haskell arrays (aka "lazy
27 -- arrays") and parallel arrays (aka "strict arrays") is that the evaluation
28 -- of two different elements of a lazy array is independent, whereas in a
29 -- strict array either non or all elements are evaluated. In other words,
30 -- when a parallel array is evaluated to WHNF, all its elements will be
31 -- evaluated to WHNF. The name parallel array indicates that all array
32 -- elements may, in general, be evaluated to WHNF in parallel without any
33 -- need to resort to speculative evaluation. This parallel evaluation
34 -- semantics is also beneficial in the sequential case, as it facilitates
35 -- loop-based array processing as known from classic array-based languages,
38 -- The interface of this module is essentially a variant of the list
39 -- component of the Prelude, but also includes some functions (such as
40 -- permutations) that are not provided for lists. The following list
41 -- operations are not supported on parallel arrays, as they would require the
42 -- availability of infinite parallel arrays: `iterate', `repeat', and `cycle'.
44 -- The current implementation is quite simple and entirely based on boxed
45 -- arrays. One disadvantage of boxed arrays is that they require to
46 -- immediately initialise all newly allocated arrays with an error thunk to
47 -- keep the garbage collector happy, even if it is guaranteed that the array
48 -- is fully initialised with different values before passing over the
49 -- user-visible interface boundary. Currently, no effort is made to use
50 -- raw memory copy operations to speed things up.
52 --- TODO ----------------------------------------------------------------------
54 -- * We probably want a standard library `PArray' in addition to the prelude
55 -- extension in the same way as the standard library `List' complements the
56 -- list functions from the prelude.
58 -- * Currently, functions that emphasis the constructor-based definition of
59 -- lists (such as, head, last, tail, and init) are not supported.
61 -- Is it worthwhile to support the string processing functions lines,
62 -- words, unlines, and unwords? (Currently, they are not implemented.)
64 -- It can, however, be argued that it would be worthwhile to include them
65 -- for completeness' sake; maybe only in the standard library `PArray'.
67 -- * Prescans are often more useful for array programming than scans. Shall
68 -- we include them into the Prelude or the library?
70 -- * Due to the use of the iterator `loop', we could define some fusion rules
73 -- * We might want to add bounds checks that can be deactivated.
77 -- [::], -- Built-in syntax
79 mapP, -- :: (a -> b) -> [:a:] -> [:b:]
80 (+:+), -- :: [:a:] -> [:a:] -> [:a:]
81 filterP, -- :: (a -> Bool) -> [:a:] -> [:a:]
82 concatP, -- :: [:[:a:]:] -> [:a:]
83 concatMapP, -- :: (a -> [:b:]) -> [:a:] -> [:b:]
84 -- head, last, tail, init, -- it's not wise to use them on arrays
85 nullP, -- :: [:a:] -> Bool
86 lengthP, -- :: [:a:] -> Int
87 (!:), -- :: [:a:] -> Int -> a
88 foldlP, -- :: (a -> b -> a) -> a -> [:b:] -> a
89 foldl1P, -- :: (a -> a -> a) -> [:a:] -> a
90 scanlP, -- :: (a -> b -> a) -> a -> [:b:] -> [:a:]
91 scanl1P, -- :: (a -> a -> a) -> [:a:] -> [:a:]
92 foldrP, -- :: (a -> b -> b) -> b -> [:a:] -> b
93 foldr1P, -- :: (a -> a -> a) -> [:a:] -> a
94 scanrP, -- :: (a -> b -> b) -> b -> [:a:] -> [:b:]
95 scanr1P, -- :: (a -> a -> a) -> [:a:] -> [:a:]
96 -- iterate, repeat, -- parallel arrays must be finite
97 singletonP, -- :: a -> [:a:]
99 replicateP, -- :: Int -> a -> [:a:]
100 -- cycle, -- parallel arrays must be finite
101 takeP, -- :: Int -> [:a:] -> [:a:]
102 dropP, -- :: Int -> [:a:] -> [:a:]
103 splitAtP, -- :: Int -> [:a:] -> ([:a:],[:a:])
104 takeWhileP, -- :: (a -> Bool) -> [:a:] -> [:a:]
105 dropWhileP, -- :: (a -> Bool) -> [:a:] -> [:a:]
106 spanP, -- :: (a -> Bool) -> [:a:] -> ([:a:], [:a:])
107 breakP, -- :: (a -> Bool) -> [:a:] -> ([:a:], [:a:])
108 -- lines, words, unlines, unwords, -- is string processing really needed
109 reverseP, -- :: [:a:] -> [:a:]
110 andP, -- :: [:Bool:] -> Bool
111 orP, -- :: [:Bool:] -> Bool
112 anyP, -- :: (a -> Bool) -> [:a:] -> Bool
113 allP, -- :: (a -> Bool) -> [:a:] -> Bool
114 elemP, -- :: (Eq a) => a -> [:a:] -> Bool
115 notElemP, -- :: (Eq a) => a -> [:a:] -> Bool
116 lookupP, -- :: (Eq a) => a -> [:(a, b):] -> Maybe b
117 sumP, -- :: (Num a) => [:a:] -> a
118 productP, -- :: (Num a) => [:a:] -> a
119 maximumP, -- :: (Ord a) => [:a:] -> a
120 minimumP, -- :: (Ord a) => [:a:] -> a
121 zipP, -- :: [:a:] -> [:b:] -> [:(a, b) :]
122 zip3P, -- :: [:a:] -> [:b:] -> [:c:] -> [:(a, b, c):]
123 zipWithP, -- :: (a -> b -> c) -> [:a:] -> [:b:] -> [:c:]
124 zipWith3P, -- :: (a -> b -> c -> d) -> [:a:]->[:b:]->[:c:]->[:d:]
125 unzipP, -- :: [:(a, b) :] -> ([:a:], [:b:])
126 unzip3P, -- :: [:(a, b, c):] -> ([:a:], [:b:], [:c:])
128 -- overloaded functions
130 enumFromToP, -- :: Enum a => a -> a -> [:a:]
131 enumFromThenToP, -- :: Enum a => a -> a -> a -> [:a:]
133 -- the following functions are not available on lists
135 toP, -- :: [a] -> [:a:]
136 fromP, -- :: [:a:] -> [a]
137 sliceP, -- :: Int -> Int -> [:e:] -> [:e:]
138 foldP, -- :: (e -> e -> e) -> e -> [:e:] -> e
139 fold1P, -- :: (e -> e -> e) -> [:e:] -> e
140 permuteP, -- :: [:Int:] -> [:e:] -> [:e:]
141 bpermuteP, -- :: [:Int:] -> [:e:] -> [:e:]
142 dpermuteP, -- :: [:Int:] -> [:e:] -> [:e:] -> [:e:]
143 crossP, -- :: [:a:] -> [:b:] -> [:(a, b):]
144 crossMapP, -- :: [:a:] -> (a -> [:b:]) -> [:(a, b):]
145 indexOfP -- :: (a -> Bool) -> [:a:] -> [:Int:]
152 import GHC.ST ( ST(..), runST )
153 import GHC.Base ( Int#, Array#, Int(I#), MutableArray#, newArray#,
154 unsafeFreezeArray#, indexArray#, writeArray#, (<#), (>=#) )
158 infix 4 `elemP`, `notElemP`
161 -- representation of parallel arrays
162 -- ---------------------------------
164 -- this rather straight forward implementation maps parallel arrays to the
165 -- internal representation used for standard Haskell arrays in GHC's Prelude
166 -- (EXPORTED ABSTRACTLY)
168 -- * This definition *must* be kept in sync with `TysWiredIn.parrTyCon'!
170 data [::] e = PArr Int# (Array# e)
173 -- exported operations on parallel arrays
174 -- --------------------------------------
176 -- operations corresponding to list operations
179 mapP :: (a -> b) -> [:a:] -> [:b:]
180 mapP f = fst . loop (mapEFL f) noAL
182 (+:+) :: [:a:] -> [:a:] -> [:a:]
183 a1 +:+ a2 = fst $ loop (mapEFL sel) noAL (enumFromToP 0 (len1 + len2 - 1))
184 -- we can't use the [:x..y:] form here for tedious
185 -- reasons to do with the typechecker and the fact that
186 -- `enumFromToP' is defined in the same module
191 sel i | i < len1 = a1!:i
192 | otherwise = a2!:(i - len1)
194 filterP :: (a -> Bool) -> [:a:] -> [:a:]
195 filterP p = fst . loop (filterEFL p) noAL
197 concatP :: [:[:a:]:] -> [:a:]
198 concatP xss = foldlP (+:+) [::] xss
200 concatMapP :: (a -> [:b:]) -> [:a:] -> [:b:]
201 concatMapP f = concatP . mapP f
203 -- head, last, tail, init, -- it's not wise to use them on arrays
205 nullP :: [:a:] -> Bool
209 lengthP :: [:a:] -> Int
210 lengthP (PArr n# _) = I# n#
212 (!:) :: [:a:] -> Int -> a
215 foldlP :: (a -> b -> a) -> a -> [:b:] -> a
216 foldlP f z = snd . loop (foldEFL (flip f)) z
218 foldl1P :: (a -> a -> a) -> [:a:] -> a
219 foldl1P _ [::] = error "Prelude.foldl1P: empty array"
220 foldl1P f a = snd $ loopFromTo 1 (lengthP a - 1) (foldEFL f) (a!:0) a
222 scanlP :: (a -> b -> a) -> a -> [:b:] -> [:a:]
223 scanlP f z = fst . loop (scanEFL (flip f)) z
225 scanl1P :: (a -> a -> a) -> [:a:] -> [:a:]
226 scanl1P _ [::] = error "Prelude.scanl1P: empty array"
227 scanl1P f a = fst $ loopFromTo 1 (lengthP a - 1) (scanEFL f) (a!:0) a
229 foldrP :: (a -> b -> b) -> b -> [:a:] -> b
230 foldrP = error "Prelude.foldrP: not implemented yet" -- FIXME
232 foldr1P :: (a -> a -> a) -> [:a:] -> a
233 foldr1P = error "Prelude.foldr1P: not implemented yet" -- FIXME
235 scanrP :: (a -> b -> b) -> b -> [:a:] -> [:b:]
236 scanrP = error "Prelude.scanrP: not implemented yet" -- FIXME
238 scanr1P :: (a -> a -> a) -> [:a:] -> [:a:]
239 scanr1P = error "Prelude.scanr1P: not implemented yet" -- FIXME
241 -- iterate, repeat -- parallel arrays must be finite
243 singletonP :: a -> [:a:]
244 {-# INLINE singletonP #-}
245 singletonP e = replicateP 1 e
248 {- NOINLINE emptyP #-}
249 emptyP = replicateP 0 undefined
252 replicateP :: Int -> a -> [:a:]
253 {-# INLINE replicateP #-}
254 replicateP n e = runST (do
255 marr# <- newArray n e
258 -- cycle -- parallel arrays must be finite
260 takeP :: Int -> [:a:] -> [:a:]
261 takeP n = sliceP 0 (n - 1)
263 dropP :: Int -> [:a:] -> [:a:]
264 dropP n a = sliceP n (lengthP a - 1) a
266 splitAtP :: Int -> [:a:] -> ([:a:],[:a:])
267 splitAtP n xs = (takeP n xs, dropP n xs)
269 takeWhileP :: (a -> Bool) -> [:a:] -> [:a:]
270 takeWhileP = error "Prelude.takeWhileP: not implemented yet" -- FIXME
272 dropWhileP :: (a -> Bool) -> [:a:] -> [:a:]
273 dropWhileP = error "Prelude.dropWhileP: not implemented yet" -- FIXME
275 spanP :: (a -> Bool) -> [:a:] -> ([:a:], [:a:])
276 spanP = error "Prelude.spanP: not implemented yet" -- FIXME
278 breakP :: (a -> Bool) -> [:a:] -> ([:a:], [:a:])
279 breakP p = spanP (not . p)
281 -- lines, words, unlines, unwords, -- is string processing really needed
283 reverseP :: [:a:] -> [:a:]
284 reverseP a = permuteP (enumFromThenToP (len - 1) (len - 2) 0) a
285 -- we can't use the [:x, y..z:] form here for tedious
286 -- reasons to do with the typechecker and the fact that
287 -- `enumFromThenToP' is defined in the same module
291 andP :: [:Bool:] -> Bool
292 andP = foldP (&&) True
294 orP :: [:Bool:] -> Bool
295 orP = foldP (||) True
297 anyP :: (a -> Bool) -> [:a:] -> Bool
298 anyP p = orP . mapP p
300 allP :: (a -> Bool) -> [:a:] -> Bool
301 allP p = andP . mapP p
303 elemP :: (Eq a) => a -> [:a:] -> Bool
304 elemP x = anyP (== x)
306 notElemP :: (Eq a) => a -> [:a:] -> Bool
307 notElemP x = allP (/= x)
309 lookupP :: (Eq a) => a -> [:(a, b):] -> Maybe b
310 lookupP = error "Prelude.lookupP: not implemented yet" -- FIXME
312 sumP :: (Num a) => [:a:] -> a
315 productP :: (Num a) => [:a:] -> a
316 productP = foldP (*) 1
318 maximumP :: (Ord a) => [:a:] -> a
319 maximumP [::] = error "Prelude.maximumP: empty parallel array"
320 maximumP xs = fold1P max xs
322 minimumP :: (Ord a) => [:a:] -> a
323 minimumP [::] = error "Prelude.minimumP: empty parallel array"
324 minimumP xs = fold1P min xs
326 zipP :: [:a:] -> [:b:] -> [:(a, b):]
329 zip3P :: [:a:] -> [:b:] -> [:c:] -> [:(a, b, c):]
330 zip3P = zipWith3P (,,)
332 zipWithP :: (a -> b -> c) -> [:a:] -> [:b:] -> [:c:]
333 zipWithP f a1 a2 = let
336 len = len1 `min` len2
338 fst $ loopFromTo 0 (len - 1) combine 0 a1
340 combine e1 i = (Just $ f e1 (a2!:i), i + 1)
342 zipWith3P :: (a -> b -> c -> d) -> [:a:]->[:b:]->[:c:]->[:d:]
343 zipWith3P f a1 a2 a3 = let
347 len = len1 `min` len2 `min` len3
349 fst $ loopFromTo 0 (len - 1) combine 0 a1
351 combine e1 i = (Just $ f e1 (a2!:i) (a3!:i), i + 1)
353 unzipP :: [:(a, b):] -> ([:a:], [:b:])
354 unzipP a = (fst $ loop (mapEFL fst) noAL a, fst $ loop (mapEFL snd) noAL a)
355 -- FIXME: these two functions should be optimised using a tupled custom loop
356 unzip3P :: [:(a, b, c):] -> ([:a:], [:b:], [:c:])
357 unzip3P x = (fst $ loop (mapEFL fst3) noAL x,
358 fst $ loop (mapEFL snd3) noAL x,
359 fst $ loop (mapEFL trd3) noAL x)
368 instance Eq a => Eq [:a:] where
369 a1 == a2 | lengthP a1 == lengthP a2 = andP (zipWithP (==) a1 a2)
372 instance Ord a => Ord [:a:] where
373 compare a1 a2 = case foldlP combineOrdering EQ (zipWithP compare a1 a2) of
374 EQ | lengthP a1 == lengthP a2 -> EQ
375 | lengthP a1 < lengthP a2 -> LT
378 combineOrdering EQ EQ = EQ
379 combineOrdering EQ other = other
380 combineOrdering other _ = other
382 instance Functor [::] where
385 instance Monad [::] where
386 m >>= k = foldrP ((+:+) . k ) [::] m
387 m >> k = foldrP ((+:+) . const k) [::] m
391 instance Show a => Show [:a:] where
392 showsPrec _ = showPArr . fromP
394 showPArr [] s = "[::]" ++ s
395 showPArr (x:xs) s = "[:" ++ shows x (showPArr' xs s)
397 showPArr' [] s = ":]" ++ s
398 showPArr' (y:ys) s = ',' : shows y (showPArr' ys s)
400 instance Read a => Read [:a:] where
401 readsPrec _ a = [(toP v, rest) | (v, rest) <- readPArr a]
403 readPArr = readParen False (\r -> do
407 (do { (":]", t) <- lex s; return ([], t) }) ++
408 (do { (x, t) <- reads s; (xs, u) <- readPArr2 t; return (x:xs, u) })
411 (do { (":]", t) <- lex s; return ([], t) }) ++
412 (do { (",", t) <- lex s; (x, u) <- reads t; (xs, v) <- readPArr2 u;
415 -- overloaded functions
418 -- Ideally, we would like `enumFromToP' and `enumFromThenToP' to be members of
419 -- `Enum'. On the other hand, we really do not want to change `Enum'. Thus,
420 -- for the moment, we hope that the compiler is sufficiently clever to
421 -- properly fuse the following definitions.
423 enumFromToP :: Enum a => a -> a -> [:a:]
424 enumFromToP x0 y0 = mapP toEnum (eftInt (fromEnum x0) (fromEnum y0))
426 eftInt x y = scanlP (+) x $ replicateP (y - x + 1) 1
428 enumFromThenToP :: Enum a => a -> a -> a -> [:a:]
429 enumFromThenToP x0 y0 z0 =
430 mapP toEnum (efttInt (fromEnum x0) (fromEnum y0) (fromEnum z0))
432 efttInt x y z = scanlP (+) x $
433 replicateP (abs (z - x) `div` abs delta + 1) delta
437 -- the following functions are not available on lists
440 -- create an array from a list (EXPORTED)
443 toP l = fst $ loop store l (replicateP (length l) ())
445 store _ (x:xs) = (Just x, xs)
447 -- convert an array to a list (EXPORTED)
449 fromP :: [:a:] -> [a]
450 fromP a = [a!:i | i <- [0..lengthP a - 1]]
452 -- cut a subarray out of an array (EXPORTED)
454 sliceP :: Int -> Int -> [:e:] -> [:e:]
456 fst $ loopFromTo (0 `max` from) (to `min` (lengthP a - 1)) (mapEFL id) noAL a
458 -- parallel folding (EXPORTED)
460 -- * the first argument must be associative; otherwise, the result is undefined
462 foldP :: (e -> e -> e) -> e -> [:e:] -> e
465 -- parallel folding without explicit neutral (EXPORTED)
467 -- * the first argument must be associative; otherwise, the result is undefined
469 fold1P :: (e -> e -> e) -> [:e:] -> e
472 -- permute an array according to the permutation vector in the first argument
475 permuteP :: [:Int:] -> [:e:] -> [:e:]
477 | isLen /= esLen = error "GHC.PArr: arguments must be of the same length"
478 | otherwise = runST (do
479 marr <- newArray isLen noElem
483 noElem = error "GHC.PArr.permuteP: I do not exist!"
484 -- unlike standard Haskell arrays, this value represents an
489 -- permute an array according to the back-permutation vector in the first
490 -- argument (EXPORTED)
492 -- * the permutation vector must represent a surjective function; otherwise,
493 -- the result is undefined
495 bpermuteP :: [:Int:] -> [:e:] -> [:e:]
496 bpermuteP is es = fst $ loop (mapEFL (es!:)) noAL is
498 -- permute an array according to the permutation vector in the first
499 -- argument, which need not be surjective (EXPORTED)
501 -- * any elements in the result that are not covered by the permutation
502 -- vector assume the value of the corresponding position of the third
505 dpermuteP :: [:Int:] -> [:e:] -> [:e:] -> [:e:]
507 | isLen /= esLen = error "GHC.PArr: arguments must be of the same length"
508 | otherwise = runST (do
509 marr <- newArray dftLen noElem
510 _ <- trans 0 (isLen - 1) marr dft copyOne noAL
514 noElem = error "GHC.PArr.permuteP: I do not exist!"
515 -- unlike standard Haskell arrays, this value represents an
521 copyOne e _ = (Just e, noAL)
523 -- computes the cross combination of two arrays (EXPORTED)
525 crossP :: [:a:] -> [:b:] -> [:(a, b):]
526 crossP a1 a2 = fst $ loop combine (0, 0) $ replicateP len ()
532 combine _ (i, j) = (Just $ (a1!:i, a2!:j), next)
534 next | (i + 1) == len1 = (0 , j + 1)
535 | otherwise = (i + 1, j)
537 {- An alternative implementation
538 * The one above is certainly better for flattened code, but here where we
539 are handling boxed arrays, the trade off is less clear. However, I
540 think, the above one is still better.
545 x1 = concatP $ mapP (replicateP len2) a1
546 x2 = concatP $ replicateP len1 a2
551 -- |Compute a cross of an array and the arrays produced by the given function
552 -- for the elements of the first array.
554 crossMapP :: [:a:] -> (a -> [:b:]) -> [:(a, b):]
557 segd = mapP lengthP bs
558 as = zipWithP replicateP segd a
560 zipP (concatP as) (concatP bs)
562 {- The following may seem more straight forward, but the above is very cheap
563 with segmented arrays, as `mapP lengthP', `zipP', and `concatP' are
564 constant time, and `map f' uses the lifted version of `f'.
566 crossMapP a f = concatP $ mapP (\x -> mapP ((,) x) (f x)) a
570 -- computes an index array for all elements of the second argument for which
571 -- the predicate yields `True' (EXPORTED)
573 indexOfP :: (a -> Bool) -> [:a:] -> [:Int:]
574 indexOfP p a = fst $ loop calcIdx 0 a
576 calcIdx e idx | p e = (Just idx, idx + 1)
577 | otherwise = (Nothing , idx )
580 -- auxiliary functions
581 -- -------------------
583 -- internally used mutable boxed arrays
585 data MPArr s e = MPArr Int# (MutableArray# s e)
587 -- allocate a new mutable array that is pre-initialised with a given value
589 newArray :: Int -> e -> ST s (MPArr s e)
590 {-# INLINE newArray #-}
591 newArray (I# n#) e = ST $ \s1# ->
592 case newArray# n# e s1# of { (# s2#, marr# #) ->
593 (# s2#, MPArr n# marr# #)}
595 -- convert a mutable array into the external parallel array representation
597 mkPArr :: Int -> MPArr s e -> ST s [:e:]
598 {-# INLINE mkPArr #-}
599 mkPArr (I# n#) (MPArr _ marr#) = ST $ \s1# ->
600 case unsafeFreezeArray# marr# s1# of { (# s2#, arr# #) ->
601 (# s2#, PArr n# arr# #) }
603 -- general array iterator
605 -- * corresponds to `loopA' from ``Functional Array Fusion'', Chakravarty &
608 loop :: (e -> acc -> (Maybe e', acc)) -- mapping & folding, once per element
609 -> acc -- initial acc value
610 -> [:e:] -- input array
613 loop mf acc arr = loopFromTo 0 (lengthP arr - 1) mf acc arr
615 -- general array iterator with bounds
617 loopFromTo :: Int -- from index
619 -> (e -> acc -> (Maybe e', acc))
623 {-# INLINE loopFromTo #-}
624 loopFromTo from to mf start arr = runST (do
625 marr <- newArray (to - from + 1) noElem
626 (n', acc) <- trans from to marr arr mf start
627 arr' <- mkPArr n' marr
630 noElem = error "GHC.PArr.loopFromTo: I do not exist!"
631 -- unlike standard Haskell arrays, this value represents an
634 -- actual loop body of `loop'
636 -- * for this to be really efficient, it has to be translated with the
637 -- constructor specialisation phase "SpecConstr" switched on; as of GHC 5.03
638 -- this requires an optimisation level of at least -O2
640 trans :: Int -- index of first elem to process
641 -> Int -- index of last elem to process
642 -> MPArr s e' -- destination array
643 -> [:e:] -- source array
644 -> (e -> acc -> (Maybe e', acc)) -- mutator
645 -> acc -- initial accumulator
646 -> ST s (Int, acc) -- final destination length/final acc
648 trans from to marr arr mf start = trans' from 0 start
650 trans' arrOff marrOff acc
651 | arrOff > to = return (marrOff, acc)
653 let (oe', acc') = mf (arr `indexPArr` arrOff) acc
654 marrOff' <- case oe' of
655 Nothing -> return marrOff
657 writeMPArr marr marrOff e'
659 trans' (arrOff + 1) marrOff' acc'
661 -- Permute the given elements into the mutable array.
663 permute :: MPArr s e -> [:Int:] -> [:e:] -> ST s ()
664 permute marr is es = perm 0
668 | otherwise = writeMPArr marr (is!:i) (es!:i) >> perm (i + 1)
673 -- common patterns for using `loop'
676 -- initial value for the accumulator when the accumulator is not needed
681 -- `loop' mutator maps a function over array elements
683 mapEFL :: (e -> e') -> (e -> () -> (Maybe e', ()))
684 {-# INLINE mapEFL #-}
685 mapEFL f = \e _ -> (Just $ f e, ())
687 -- `loop' mutator that filter elements according to a predicate
689 filterEFL :: (e -> Bool) -> (e -> () -> (Maybe e, ()))
690 {-# INLINE filterEFL #-}
691 filterEFL p = \e _ -> if p e then (Just e, ()) else (Nothing, ())
693 -- `loop' mutator for array folding
695 foldEFL :: (e -> acc -> acc) -> (e -> acc -> (Maybe (), acc))
696 {-# INLINE foldEFL #-}
697 foldEFL f = \e a -> (Nothing, f e a)
699 -- `loop' mutator for array scanning
701 scanEFL :: (e -> acc -> acc) -> (e -> acc -> (Maybe acc, acc))
702 {-# INLINE scanEFL #-}
703 scanEFL f = \e a -> (Just a, f e a)
705 -- elementary array operations
708 -- unlifted array indexing
710 indexPArr :: [:e:] -> Int -> e
711 {-# INLINE indexPArr #-}
712 indexPArr (PArr n# arr#) (I# i#)
713 | i# >=# 0# && i# <# n# =
714 case indexArray# arr# i# of (# e #) -> e
715 | otherwise = error $ "indexPArr: out of bounds parallel array index; " ++
716 "idx = " ++ show (I# i#) ++ ", arr len = "
719 -- encapsulate writing into a mutable array into the `ST' monad
721 writeMPArr :: MPArr s e -> Int -> e -> ST s ()
722 {-# INLINE writeMPArr #-}
723 writeMPArr (MPArr n# marr#) (I# i#) e
724 | i# >=# 0# && i# <# n# =
726 case writeArray# marr# i# e s# of s'# -> (# s'#, () #)
727 | otherwise = error $ "writeMPArr: out of bounds parallel array index; " ++
728 "idx = " ++ show (I# i#) ++ ", arr len = "
731 #endif /* __HADDOCK__ */