1

Why are we calling a flip of structure a "sequence" and why are we talking about "traverse" and "Traversal" ?

I'm adding the implementation in haskell of these concepts as a matter to discussion...

class (Functor t, Foldable t) => Traversable t where
    {-# MINIMAL traverse | sequenceA #-}

    -- | Map each element of a structure to an action, evaluate these actions
    -- from left to right, and collect the results. For a version that ignores
    -- the results see 'Data.Foldable.traverse_'.
    traverse :: Applicative f => (a -> f b) -> t a -> f (t b)
    traverse f = sequenceA . fmap f

    -- | Evaluate each action in the structure from left to right, and
    -- and collect the results. For a version that ignores the results
    -- see 'Data.Foldable.sequenceA_'.
    sequenceA :: Applicative f => t (f a) -> f (t a)
    sequenceA = traverse id
duplode
  • 33,731
  • 7
  • 79
  • 150
Nicolas Henin
  • 3,244
  • 2
  • 21
  • 42
  • 3
    `sequence` (verb): turn a sequence (noun) of applicative "actions" "inside" a traversable "container" into one applicative "action" producing the sequence of results. For lists, it can be defined as `sequenceA = foldr (liftA2 (:)) (pure [])`. `traverse` could be called `mapA` since it's parallel to `mapM`. I guess mapping is kind of a traversing. – Will Ness Jun 19 '18 at 16:51
  • 1
    also, for lists again, `sequence [] = return [] ; sequence (x:xs) = do { x <- x; xs <- sequence xs; return (x:xs) }` where all "computations" `xs` are known in advance, so full power of Monad's being able to create new computations based on results of previously-run computations (as in `y <- foo x`) is actually *not* needed. Hence the Applicative Functor, a less powerful, more general Functor than Monadic Functor. – Will Ness Jun 20 '18 at 06:24

2 Answers2

3

It's "to sequence", not "a". I.e. "Arrange in a particular order", here from left to right. And it is a generalization of sequence :: Monad m => [m a] -> m [a] (note the old base version), which may make the name more obvious.

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
  • ok cool, it makes sense .. and then why traverse / traversal ? – Nicolas Henin Jun 19 '18 at 20:35
  • That's much harder for me to say. Try to look at the papers linked in http://hackage.haskell.org/package/base-4.11.1.0/docs/Data-Traversable.html? – Alexey Romanov Jun 19 '18 at 20:55
  • 1
    "traverse" is straightforward English: "travel across or through". i.e. enumerate in some kind of linear fashion all elements `a` inside a container `t a`. like enumerating nodes in a binary tree. or enumerating [a tree's fringe](http://www.dreamsongs.com/10ideas.html). – Will Ness Jun 20 '18 at 06:19
  • What I dislike a bit is that `sequenceA` seems more basic (just look at the descriptions), but the class is still named for `traverse` :) – Alexey Romanov Jun 20 '18 at 11:39
3

Let's begin by considering fmap:

fmap :: Functor t => (a -> b) -> t a -> t b

We can describe what it does as finding all a values in a t a and applying a function to them. Note that, infinite structure shenanigans aside, the order in which the implementation of fmap reaches the a values to modify them doesn't matter as far as the final result is concerned.

Now let's have a look at traverse:

traverse :: (Applicative f, Traversable t) => (a -> f b) -> t a -> f (t b)

Like fmap, traverse also involves applying a function to values found in a structure (it's no wonder traverse's forerunner was called mapM). traverse, however, also produces applicative effects for each of the a values (the f in a -> f b), and it involves combining those effects in some order to get the overall f (t b) result. In general (i.e. as long as f isn't a commutative applicative, such as Maybe), the order of effects affects the result. That being so, any Traversable instance corresponds to a specific order in which the values in the structure will be visited. The name "traverse" (that is, as Will Ness points out, "travel across or through") is meant to convey this sense of direction.

On a related note, traverse can be decomposed into a plain mapping which produces effects followed by the sequencing of those effects...

sequenceA :: (Applicative f, Traversable t) => t (f a) -> f (t a)

traverse f = sequenceA . fmap f
sequenceA = traverse id

... ergo the "sequence" name.

It is also worth emphasising that traverse does capture various ways of going through a structure and doing things at each stop (cf. for being the name for flip traverse). In particular, we recover fmap by picking Identity as the Applicative functor (i.e. by not actually generating any effects), and foldMap (that is, list-like folding) by picking Monoid m => Const m instead. Things we can't do with traverse include dropping, duplicating or rearranging elements -- it doesn't allow tearing down a data structure in arbitrary ways like a general fold/catamorphism does. With traverse, we can move through a Traversable structure, but we can't reshape it.

duplode
  • 33,731
  • 7
  • 79
  • 150
  • Thanks @duplode ! – Nicolas Henin Jun 21 '18 at 17:43
  • 1
    @NicolasHenin You are welcome. Something I forgot to mention: the most popular name in Haskell for the dual "flip of a structure" is [`distribute :: (Functor f, Distributive g) => f (g a) -> g (f a)`](http://hackage.haskell.org/package/distributive-0.5.3/docs/Data-Distributive.html). (Then again, one of the key papers about `Traversable` uses `dist` as a name for `sequenceA`, which, I guess, only shows how hard it can be to name things.) – duplode Jun 21 '18 at 20:59