Skip to content

Commit b7f1c86

Browse files
oisdktreeowl
authored andcommitted
Faster traverse (#516)
1 parent 4dc074d commit b7f1c86

File tree

1 file changed

+73
-21
lines changed

1 file changed

+73
-21
lines changed

Data/Sequence/Internal.hs

Lines changed: 73 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -424,29 +424,81 @@ instance Foldable Seq where
424424
{-# INLINE null #-}
425425
#endif
426426

427-
#if __GLASGOW_HASKELL__ >= 708
428-
-- The natural definition of traverse, used for implementations that don't
429-
-- support coercions, `fmap`s into each `Elem`, then `fmap`s again over the
430-
-- result to turn it from a `FingerTree` to a `Seq`. None of this mapping is
431-
-- necessary! We could avoid it without coercions, I believe, by writing a
432-
-- bunch of traversal functions to deal with the `Elem` stuff specially (for
433-
-- FingerTrees, Digits, and Nodes), but using coercions we only need to
434-
-- duplicate code at the FingerTree level. We coerce the `Seq a` to a
435-
-- `FingerTree a`, stripping off all the Elem junk, then use a weird FingerTree
436-
-- traversing function that coerces back to Seq within the functor.
437-
instance Traversable Seq where
438-
traverse f xs = traverseFTE f (coerce xs)
439-
440-
traverseFTE :: Applicative f => (a -> f b) -> FingerTree a -> f (Seq b)
441-
traverseFTE _f EmptyT = pure empty
442-
traverseFTE f (Single x) = Seq . Single . Elem <$> f x
443-
traverseFTE f (Deep s pr m sf) =
444-
liftA3 (\pr' m' sf' -> coerce $ Deep s pr' m' sf')
445-
(traverse f pr) (traverse (traverse f) m) (traverse f sf)
446-
#else
447427
instance Traversable Seq where
448-
traverse f (Seq xs) = Seq <$> traverse (traverse f) xs
428+
#if __GLASGOW_HASKELL__
429+
{-# INLINABLE traverse #-}
449430
#endif
431+
traverse _ (Seq EmptyT) = pure (Seq EmptyT)
432+
traverse f' (Seq (Single (Elem x'))) =
433+
(\x'' -> Seq (Single (Elem x''))) <$> f' x'
434+
traverse f' (Seq (Deep s' pr' m' sf')) =
435+
liftA3
436+
(\pr'' m'' sf'' -> Seq (Deep s' pr'' m'' sf''))
437+
(traverseDigitE f' pr')
438+
(traverseTree (traverseNodeE f') m')
439+
(traverseDigitE f' sf')
440+
where
441+
traverseTree
442+
:: Applicative f
443+
=> (Node a -> f (Node b))
444+
-> FingerTree (Node a)
445+
-> f (FingerTree (Node b))
446+
traverseTree _ EmptyT = pure EmptyT
447+
traverseTree f (Single x) = Single <$> f x
448+
traverseTree f (Deep s pr m sf) =
449+
liftA3
450+
(Deep s)
451+
(traverseDigitN f pr)
452+
(traverseTree (traverseNodeN f) m)
453+
(traverseDigitN f sf)
454+
traverseDigitE
455+
:: Applicative f
456+
=> (a -> f b) -> Digit (Elem a) -> f (Digit (Elem b))
457+
traverseDigitE f (One (Elem a)) =
458+
(\a' -> One (Elem a')) <$>
459+
f a
460+
traverseDigitE f (Two (Elem a) (Elem b)) =
461+
liftA2
462+
(\a' b' -> Two (Elem a') (Elem b'))
463+
(f a)
464+
(f b)
465+
traverseDigitE f (Three (Elem a) (Elem b) (Elem c)) =
466+
liftA3
467+
(\a' b' c' ->
468+
Three (Elem a') (Elem b') (Elem c'))
469+
(f a)
470+
(f b)
471+
(f c)
472+
traverseDigitE f (Four (Elem a) (Elem b) (Elem c) (Elem d)) =
473+
liftA3
474+
(\a' b' c' d' -> Four (Elem a') (Elem b') (Elem c') (Elem d'))
475+
(f a)
476+
(f b)
477+
(f c) <*>
478+
(f d)
479+
traverseDigitN
480+
:: Applicative f
481+
=> (Node a -> f (Node b)) -> Digit (Node a) -> f (Digit (Node b))
482+
traverseDigitN f t = traverse f t
483+
traverseNodeE
484+
:: Applicative f
485+
=> (a -> f b) -> Node (Elem a) -> f (Node (Elem b))
486+
traverseNodeE f (Node2 s (Elem a) (Elem b)) =
487+
liftA2
488+
(\a' b' -> Node2 s (Elem a') (Elem b'))
489+
(f a)
490+
(f b)
491+
traverseNodeE f (Node3 s (Elem a) (Elem b) (Elem c)) =
492+
liftA3
493+
(\a' b' c' ->
494+
Node3 s (Elem a') (Elem b') (Elem c'))
495+
(f a)
496+
(f b)
497+
(f c)
498+
traverseNodeN
499+
:: Applicative f
500+
=> (Node a -> f (Node b)) -> Node (Node a) -> f (Node (Node b))
501+
traverseNodeN f t = traverse f t
450502

451503
instance NFData a => NFData (Seq a) where
452504
rnf (Seq xs) = rnf xs

0 commit comments

Comments
 (0)