# Discussion: traversing roots and leaves

3 messages
Open this post in threaded view
|

## Discussion: traversing roots and leaves

 My proposal to move liftA2 into the Applicative class should help get fmaps out of internal nodes in traverse implementations. But there are still two trouble spots:1. The smaller trouble spot is at the root, when dealing with newtype wrappers. For example, the simplest way to write traverse for Data.Sequence.Seq would beinstance Traversable Seq where  traverse f (Seq xs) = Seq <\$> traverse f xsThe extra fmap may not be free. Today, the only fix is to manually inline the definition of the underlying traversal and manually fuse the fmaps. It works, but it's gross! We could work around this easily using an extra Traversable method:mapTraversed :: Applicative f  => (t b -> r) -> (a -> f b) -> t a -> f rbut that wouldn't help with the larger problem below.2. Leaves are really painful. Data structures that store at most one element per leaf make obvious traversals expensive. For example, in Data.Map, the obvious implementation would beinstance Traversable (Map k) where  traverse _ Tip = pure Tip  traverse f (Bin s k v l r) =    liftA3 (Bin s k) (f v) (traverse f l) (traverse f r)The trouble is that we would generate a slew of `pure Tip`s that we'd then have to combine. For instance, (Bin 1 k v Tip Tip) would give  liftA3 (Bin 1 k) (f v) (pure Tip) (pure Tip)Today we work around this by looking ahead at the children of the element we're considering, so we getfmap (\v' -> Bin 1 k v' Tip Tip) (f v)instead, which is still pretty lousy but better.It makes me rather sad to have to write disgustingly ugly Traversable instances just to avoid silly performance issues like this. Does anyone have an idea for fixing (2), and ideally simultaneously taking care of (1)?Thanks,David Feuer _______________________________________________ Libraries mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries