Make foldMap1 for Data.Tree follow the structure
treeowl opened this issue · comments
foldMap1
is implemented in terms of foldrMap1
, which is ... not great. foldMap1
should (usually) follow the natural structure of a type. Consider the case where someone decides to use foldMap1
to implement their own copy of last
:
import Data.Semigroup (Last (..))
myLast :: Tree a -> a
myLast = getLast . foldMap1 Last
As currently implemented, this will walk the entire tree in pre-order, which could run us into trouble in an infinite subtree, or slow us down with a large one.
@meooow25 Let's get this fixed before release (very, very soon).
Are there any other folds that accidentally got overly linearized like this? The strict folds are inherently linear, I believe.
I wasn't aware that this is something to consider, but I can see the utility of implementing it that way.
Are there any other folds that accidentally got overly linearized like this?
foldMap
is defined via Traversable
, so that should be fine. I don't think there is anything else.
Yes, foldMap
and foldMap1
strictness always require careful consideration. Consider
import Data.Functor.Reverse
data Stream a = a :< Stream a
deriving Foldable
data Foo a = Foo (Stream a) (Reverse Stream a)
deriving Foldable
The derived foldMap
for Foo
will correctly support folding from either end, despite the fact that foldr
will never reach the right side and foldl
will never reach the left side.