TL;DR: maybe we can think of this as combining disjoint empty & non-empty cases of folds.
Every time I’ve wanted to define something like this I’ve found myself dissatisfied because of this asymmetry.
Looking at it from another angle, I frequently encounter a vaguely similar situation with folds: given some collection which can be empty or non-, I want to fold over it with a function if non-empty, or return a default value if empty:
foldr1OrDefault :: Foldable t => (a -> a -> a) -> a -> t a -> a
foldr1OrDefault f z t
| null t = z
| otherwise = foldr1 f t
This is a bit like Control.Lens.Fold.foldBy in lens, except that the combining function f does not receive z at any point. Quite useful when you have a Semigroup but not a Monoid, or when you otherwise want to treat the empty case specially.
fromMaybe is a special case of this function, without the conceit of pretending that Maybe can hold multiple values. I’ve sometimes involved Maybe in this construction for just that reason when e.g. a is a Semigroup:
fold1Maybe :: (Foldable t, Semigroup a) => t a -> Maybe a
fold1Maybe = foldMap Just
fold1OrDefault :: (Foldable t, Semigroup a) => a -> t a -> a
fold1OrDefault z = fromMaybe z . foldMap Just
(All of these names are intentionally bad because I don’t want to propose adding these functions anywhere just yet.)
For Either (and These for that matter), a full generalization also has to deal with the extra information in the null case, i.e. Either b a would need (b -> a) instead of a:
fromEither :: (b -> a) -> Either b a -> a
fromEither f = either f id
I’m surprised about once every six months that this doesn’t exist (and then surprised again when consulting the types that fromLeft/fromRight aren’t either this *or* analogous to fromJust).
All of which is to say, I think I would prefer to have the generality of this fromEither to the a -> Either a a -> a version, but it’d be nice to figure out a way to see it as a fold, too. Maybe the Bifoldable1 instance for Either has something to contribute here?