Is it possible to implement foldl / foldr using fuzzy fold?

By unstable fold, I mean a hypothetical operation of primitive bending for associative operators, which does not guarantee any ordering. That is, (fold + 0 [abcd]) can be (+ (+ ab) (+ cd)) or (+ (+ (+ ab) c) d) .

Given that this operation is smooth, very paralyzed, and universal, I thought about including it with map and concat as the only list primitives for my non-recursive minimalist language. I managed to implement most of the list functions with it, but not third-party folds foldl / foldr . Is it possible?

+6
source share
2 answers

If you have fold and map , that is universal. The slogan here is foldr made of monoids. In fact, the standard haskell typeclass Foldable implements foldr and foldl in this way.

The trick is that the set of endomorphisms over the set forms a monoid in the composition of functions with an identical function as an identity.

Note that foldr and foldl are inherently consistent. So, this trick should discard any parallelism that you have when implementing fold and map . Essentially, the foldMap coding in foldMap is the encoding of a deferred sequential calculation to a potentially unordered one. That's why I recommend using foldMap by foldr when possible - it supports implicit parallelism when possible, but equivalent to expressive power.

EDIT: All in one place

Define the set of endomorphisms over a

 newtype Endo a = Endo { appEndo :: a -> a } instance Monoid (Endo a) where mempty = Endo id Endo f `mappend` Endo g = Endo (f . g) 

then in folding we see a definition for foldr

 foldr fzt = appEndo (foldMap (Endo . f) t) z 

this uses foldMap , which has type Monoid m => (a -> m) -> ta -> m (where t is the collection we are adding, we can pretend that now it is a list giving Monoid m => (a -> m) -> [a] -> m and equivalent

 foldMap f ls = fold (map f ls) 

where fold is the monoid fold. If you have an unordered fold fold' :: (a -> a -> a) -> a -> [a] -> a , then it's simple

 fold = fold' mappend mempty 

So

 foldr fzt = appEndo (foldMap (Endo . f) t) z = appEndo (fold (map (Endo . f) t)) z = appEndo (fold' mappend mempty (map (Endo . f) t)) z = appEndo (fold' (\(Endo f) (Endo g) -> Endo (f . g) (Endo id) (map (Endo . f) t)) z 

which can be further simplified to

 foldr fzt = (fold' (.) id (map ft)) z 

and reset unnecessary partners

 foldr fzt = fold' (.) id (map ft) z 

what Daniel Wagner gave as an answer. You can implement foldl same way or through foldr .

+7
source
 foldr fz xs = fold (.) id (map f xs) z 

For example, in ghci:

 *Dmwit Debug.SimpleReflect> let foldr' fz xs = foldb (.) id (map f xs) z *Dmwit Debug.SimpleReflect> foldr' fz [w,x,y] fw (fx (fyz)) *Dmwit Debug.SimpleReflect> foldr fz [w,x,y] fw (fx (fyz)) 
+3
source

All Articles