Bitraversable identifies bifunctorial data structures whose
elements can be traversed in order, performing
Applicative or
Monad actions at each element, and collecting a result
structure with the same shape.
As opposed to
Traversable data structures, which have one
variety of element on which an action can be performed,
Bitraversable data structures have two such varieties of
elements.
A definition of
bitraverse must satisfy the following laws:
where an
applicative transformation is a function
t :: (Applicative f, Applicative g) => f a -> g a
preserving the
Applicative operations:
t (pure x) ≡ pure x
t (f <*> x) ≡ t f <*> t x
and the identity functor
Identity and composition functors
Compose are from
Data.Functor.Identity and
Data.Functor.Compose.
Some simple examples are
Either and
(,):
instance Bitraversable Either where
bitraverse f _ (Left x) = Left <$> f x
bitraverse _ g (Right y) = Right <$> g y
instance Bitraversable (,) where
bitraverse f g (x, y) = (,) <$> f x <*> g y
Bitraversable relates to its superclasses in the following
ways:
bimap f g ≡ runIdentity . bitraverse (Identity . f) (Identity . g)
bifoldMap f g ≡ getConst . bitraverse (Const . f) (Const . g)
These are available as
bimapDefault and
bifoldMapDefault
respectively.
If the type is also an instance of
Traversable, then it must
satisfy (up to laziness):
traverse ≡ bitraverse pure