I recently defined a type whose fields I might fail to compute:
data Foo = Foo {x, y :: Int, others :: NonEmpty Int}
data Input
computeX, computeY :: Input -> Maybe Int
computeOthers :: Input -> Maybe (NonEmpty Int)
Now, one obvious thing I might do would be to just use liftA3:
foo :: Input -> Maybe Foo
foo i = liftA3 Foo (computeX i) (computeY i) (computeOthers i)
That works fine, but I thought it might be interesting to generalize Foo to hold Maybes as well, and then transform one type of Foo to another. In some similar cases, I could give the Foo type a type parameter and derive Traversable. Then after creating a Foo (Maybe Int), I could invert the whole thing at once with sequenceA :: Foo (Maybe Int) -> Maybe (Foo Int). But this doesn't work here, because my function doesn't give me a NonEmpty (Maybe Int), it gives me a Maybe (NonEmpty Int).
So I thought I'd try parameterizing by a functor instead:
data Foo f = Foo {x, y :: f Int, others :: f (NonEmpty Int)}
But then the question is, how do I turn a Foo Maybe into a Maybe (Foo Identity)? Obviously I can write that function by hand: it's isomorphic to the liftA3 stuff above. But is there some parallel of Traversable for this higher-order type, so that I can apply a more general function to this problem rather than re-doing it with a bespoke function?