foldl1 and foldr1
The two functions
foldl1 :: (a -> a -> a) -> t a -> a
foldr1 :: (a -> a -> a) -> t a -> a
are specialized versions of foldl and foldr for non-empty containers. In
this case, if the accumulated value is of the same type as the elements in the
container, we can get away without specifying the initial accumulator value.
Instead, we take the first or last container element (first for foldl1, last
for foldr1) as the initial accumulator value and then use the accumulation
function to combine the container elements.
Here are two possible default implementations of these functions, again using lists as an intermediate representation. They are different from the actual implementations, which are more complicated but avoid the detour via lists.
foldl1 f xs = foldl1 f $ foldMap singleton xs
foldr1 f xs = foldr1 f $ foldMap singleton xs
Again, foldMap singleton xs takes care of converting the container to a list.
And then we use list-specific versions of foldl1 and foldr1 to accumulate
the list elements. We discussed list-specific implementations of foldl1 and
foldr1 before.