0

The traverse and sequenceA function in Traversable class must satisfy the following 'naturality' laws:

t . traverse f == traverse (t . f)
t . sequenceA == sequenceA . fmap t

for every 'applicative transformation' t. But what is it?

It doesn't seem to work for instance Traversable [] for t = tail:

Prelude> tail . sequenceA $ [[1],[2,3]]
[[1,3]]
Prelude> sequenceA . fmap tail $ [[1],[2,3]]
[]

Nor for t = join (++) (repeat the list twice):

Prelude Control.Monad> join (++) . sequenceA $ [[1],[2,3]]
[[1,2],[1,3],[1,2],[1,3]]
Prelude Control.Monad> sequenceA . fmap (join (++)) $ [[1],[2,3]]
[[1,2],[1,3],[1,2],[1,3],[1,2],[1,3],[1,2],[1,3]]

So for what t they are satisfied?

Dannyu NDos
  • 2,458
  • 13
  • 32
  • 1
    Another thing to note in the `Data.Traversable` documentation is that "The naturality law is implied by parametricity." This basically means that any definition of `traverse` that passes the type checker will obey the naturality law; you don't have to worry about it. – dfeuer Dec 28 '17 at 03:14

1 Answers1

5

The Hackage page for Data.Traversable defines an applicative transformation as follows.

[A]n applicative transformation is a function

t :: (Applicative f, Applicative g) => f a -> g a

preserving the Applicative operations, i.e.

t (pure x) = pure x

t (x <*> y) = t x <*> t y

The simplest example of this would be the identity function. id is an applicative transformation. A more specific example for lists would be reverse.

reverse (pure x) = reverse [x] = [x] = pure x
-- (the (<*>) law is more difficult to show)

And you can verify in GHCi that the laws you reference do hold for reverse.

Prelude> reverse . sequenceA $ [[1], [2,3]]
[[1,3],[1,2]]
Prelude> sequenceA . fmap reverse $ [[1], [2,3]]
[[1,3],[1,2]]

Source: Data.Traversable

Silvio Mayolo
  • 62,821
  • 6
  • 74
  • 116
  • 3
    The `<*>` law is more difficult to show formally, but if you express it in terms of `concat` and `map`, I think it will become at least intuitively clear. The basic principle is that `concat (reverse (map reverse xss)) = reverse (concat xss)`. Looking at a few small examples should convince anyone that this is true. `reverse (concat [[1,2], [3,4,5]]) = [5,4,3,2,1] = concat [[5,4,3], [2,1]] = concat (reverse (map reverse [[1,2], [3,4,5]]))`, for instance. – dfeuer Dec 28 '17 at 02:59