Holes
This is another great question that can be solved with the help of leaky expressions.
First, suppose we have already defined Foldable instances.
λ> instance (Foldable f, Foldable g) => Foldable (Compose fg) where foldr = undefined
Next, an instance of Traversable. Match the pattern in the Compose argument because you know what you have to do, but leave everything else in the hole otherwise.
λ> instance (Traversable t, Traversable u) => Traversable (Compose tu) where traverse a2fb (Compose tua) = _ tua
GHC will help to throw out an error -
<interactive>:...:... Found hole '_' with type: f (Compose tub)
- in addition to the types of all variables in the field.
Relevant bindings include tua :: t (ua) (bound at ...) a2fb :: a -> fb (bound at ...) traverse :: (a -> fb) -> Compose tua -> f (Compose tub) (bound at ...)
(I chose the names of types and values so that everything is neat. Do not pay attention to the person behind the curtain.) Now the question is about the hour: how to call the value f (Compose tub) , taking into account everything else, We know
The only way to build a Compose tub is to create a t (ub) value.
It is not possible to create the value of f anything except (1) pure and (2) fmap , and we know that we cannot use pure because we are trying to collect the “side effects” of a2fb :: a -> fb here.
This leads us to the next blow to the solution.
λ> instance (Traversable t, Traversable u) => Traversable (Compose tu) where traverse a2fb (Compose tua) = fmap Compose (_ tua) <interactive>:... Found hole '_' with type: t (ua) -> f (t (ub))
Finally, we have a t . We know that t is Traversable, so try going through it.
λ> instance (Traversable t, Traversable u) => Traversable (Compose tu) where traverse a2fb (Compose tua) = fmap Compose ((\tua -> traverse _ tua) tua) <interactive>:56:138: Found hole '_' with type: ua -> f (ub)
The same deal. We know u is Traversable, so try going through it.
λ> instance (Traversable t, Traversable u) => Traversable (Compose tu) where traverse a2fb (Compose tua) = fmap Compose ((\tua -> traverse (\ua -> traverse _ ua) tua) tua) <interactive>:57:155: Found hole '_' with type: a -> fb
Tin hole for our a2fb .
λ> instance (Traversable t, Traversable u) => Traversable (Compose tu) where traverse a2fb (Compose tua) = fmap Compose ((\tua -> traverse (\ua -> traverse a2fb ua) tua) tua)
Eta-reduce to cut lambdas and you get a solution .
λ> instance (Traversable t, Traversable u) => Traversable (Compose tu) where traverse a2fb (Compose tua) = fmap Compose (traverse (traverse a2fb) tua)