Skip to content

Commit f8f7491

Browse files
committed
Simplify array traversals
I found it helpful to use `foldr` to construct `traverse` and `traverse'` for `Array`, but the result wasn't particularly clear. I doubt the fold formulation helped GHC any either. Write the traversals using explicit recursion instead.
1 parent 73e13df commit f8f7491

File tree

1 file changed

+23
-15
lines changed

1 file changed

+23
-15
lines changed

Data/HashMap/Array.hs

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ import Control.Applicative (Applicative (..), (<$>))
5757
#endif
5858
import Control.Applicative (liftA2)
5959
import Control.DeepSeq
60-
import GHC.Exts(Int(..), Int#, reallyUnsafePtrEquality#, tagToEnum#, unsafeCoerce#, State#, (+#))
60+
import GHC.Exts(Int(..), Int#, reallyUnsafePtrEquality#, tagToEnum#, unsafeCoerce#, State#)
6161
import GHC.ST (ST(..))
6262
import Control.Monad.ST (stToIO)
6363

@@ -481,22 +481,30 @@ newtype STA a = STA {_runSTA :: forall s. MutableArray# s a -> ST s (Array a)}
481481
runSTA :: Int -> STA a -> Array a
482482
runSTA !n (STA m) = runST $ new_ n >>= \ (MArray ar) -> m ar
483483

484-
traverse :: forall f a b. Applicative f => (a -> f b) -> Array a -> f (Array b)
485-
traverse f = \ !ary -> runSTA (length ary) <$> foldr go stop ary 0#
486-
where
487-
go :: a -> (Int# -> f (STA b)) -> Int# -> f (STA b)
488-
go a r i = liftA2 (\b (STA m) -> STA $ \mry# -> write (MArray mry#) (I# i) b >> m mry#) (f a) (r (i +# 1#))
489-
stop :: Int# -> f (STA b)
490-
stop _i = pure (STA (\mry# -> unsafeFreeze (MArray mry#)))
484+
traverse :: Applicative f => (a -> f b) -> Array a -> f (Array b)
485+
traverse f = \ !ary ->
486+
let
487+
!len = length ary
488+
go !i
489+
| i == len = pure $ STA $ \mary -> unsafeFreeze (MArray mary)
490+
| (# x #) <- index# ary i
491+
= liftA2 (\b (STA m) -> STA $ \mary ->
492+
write (MArray mary) i b >> m mary)
493+
(f x) (go (i + 1))
494+
in runSTA len <$> go 0
491495
{-# INLINE [1] traverse #-}
492496

493-
traverse' :: forall f a b. Applicative f => (a -> f b) -> Array a -> f (Array b)
494-
traverse' f = \ !ary -> runSTA (length ary) <$> foldr go stop ary 0#
495-
where
496-
go :: a -> (Int# -> f (STA b)) -> Int# -> f (STA b)
497-
go a r i = liftA2 (\ !b (STA m) -> STA $ \mry# -> write (MArray mry#) (I# i) b >> m mry#) (f a) (r (i +# 1#))
498-
stop :: Int# -> f (STA b)
499-
stop _i = pure (STA (\mry# -> unsafeFreeze (MArray mry#)))
497+
traverse' :: Applicative f => (a -> f b) -> Array a -> f (Array b)
498+
traverse' f = \ !ary ->
499+
let
500+
!len = length ary
501+
go !i
502+
| i == len = pure $ STA $ \mary -> unsafeFreeze (MArray mary)
503+
| (# x #) <- index# ary i
504+
= liftA2 (\ !b (STA m) -> STA $ \mary ->
505+
write (MArray mary) i b >> m mary)
506+
(f x) (go (i + 1))
507+
in runSTA len <$> go 0
500508
{-# INLINE [1] traverse' #-}
501509

502510
-- Traversing in ST, we don't need to get fancy; we

0 commit comments

Comments
 (0)