From here, class Traversable
is a Functor
and a Foldable
, and must satisfy the laws:
And Foldable
see more here. That means that it can be folded (foldMap, foldr, foldl...)
traverse
function must satisfy the laws:
naturality:
t . traverse f = traverse (t . f) for every applicative transformation t
identity
traverse Identity = Identity
composition
traverse (Compose . fmap g . f) = Compose . fmap (traverse g) . traverse f
and sequenceA:
naturality
t . sequenceA = sequenceA . fmap t for every applicative transformation t
identity
sequenceA . fmap Identity = Identity
composition
sequenceA . fmap Compose = Compose . fmap sequenceA . sequenceA
Which fact does sequenceA use: t being a Functor type, t being a Foldable type, or both?
Traversable
, as its definition says (and the laws quoted above):
class (Functor t, Foldable t) => Traversable t where
is both, a Functor
and a Foldable, by the laws it has to obey, it is not only a Functor
, is more specific than a Functor
(but still a Functor because satisfies the laws of Functor and can use the functions of its typeclass interface), and even more specific than Foldable
, hence powerful, less general, with more constraints.
And what's the fact? The definition, but why the designer of Traversable
choose those two? Because is useful, as you can see in @Daniel Wagner answer. Other examples:
instance Traversable [] where
traverse f = List.foldr cons_f (pure [])
where cons_f x ys = liftA2 (:) (f x) ys
this one uses foldr
instance Foldable [] where
elem = List.elem
foldl = List.foldl
foldl' = List.foldl'
foldl1 = List.foldl1
foldr = List.foldr
foldr1 = List.foldr1
length = List.length
maximum = List.maximum
minimum = List.minimum
null = List.null
product = List.product
sum = List.sum
toList = id
So, Traverse
is a Functor
and a Foldable
so you could use the functions of its interface when needed. (as in the example, is just an example not a justification of why the designer chooses to define Traversable
with Functor
and Foldable
), is because is useful.