Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can someone explain the traverse function in Haskell?

I am trying and failing to grok the traverse function from Data.Traversable. I am unable to see its point. Since I come from an imperative background, can someone please explain it to me in terms of an imperative loop? Pseudo-code would be much appreciated. Thanks.

like image 438
Konan Avatar asked Sep 18 '11 10:09

Konan


People also ask

What is traversable Haskell?

Class of data structures that can be traversed from left to right, performing an action on each element. Instances are expected to satisfy the listed laws. class (Functor t, Foldable t) => Traversable t where.

What is Fmap in Haskell?

You can think of fmap as either a function that takes a function and a functor and then maps that function over the functor, or you can think of it as a function that takes a function and lifts that function so that it operates on functors. Both views are correct and in Haskell, equivalent.


1 Answers

traverse is the same as fmap, except that it also allows you to run effects while you're rebuilding the data structure.

Take a look at the example from the Data.Traversable documentation.

 data Tree a = Empty | Leaf a | Node (Tree a) a (Tree a) 

The Functor instance of Tree would be:

instance Functor Tree where   fmap f Empty        = Empty   fmap f (Leaf x)     = Leaf (f x)   fmap f (Node l k r) = Node (fmap f l) (f k) (fmap f r) 

It rebuilds the entire tree, applying f to every value.

instance Traversable Tree where     traverse f Empty        = pure Empty     traverse f (Leaf x)     = Leaf <$> f x     traverse f (Node l k r) = Node <$> traverse f l <*> f k <*> traverse f r 

The Traversable instance is almost the same, except the constructors are called in applicative style. This means that we can have (side-)effects while rebuilding the tree. Applicative is almost the same as monads, except that effects cannot depend on previous results. In this example it means that you could not do something different to the right branch of a node depending on the results of rebuilding the left branch for example.

For historical reasons, the Traversable class also contains a monadic version of traverse called mapM. For all intents and purposes mapM is the same as traverse - it exists as a separate method because Applicative only later became a superclass of Monad.

If you would implement this in an impure language, fmap would be the same as traverse, as there is no way to prevent side-effects. You can't implement it as a loop, as you have to traverse your data structure recursively. Here's a small example how I would do it in Javascript:

Node.prototype.traverse = function (f) {   return new Node(this.l.traverse(f), f(this.k), this.r.traverse(f)); } 

Implementing it like this limits you to the effects that the language allows though. If you f.e. want non-determinism (which the list instance of Applicative models) and your language doesn't have it built-in, you're out of luck.

like image 189
Sjoerd Visscher Avatar answered Sep 20 '22 15:09

Sjoerd Visscher