-3

In Foldable t, foldMap is defined based on foldr

foldMap :: Monoid m => (a -> m) -> t a -> m
foldMap f = foldr (mappend . f) mempty

Can foldMap f be defined equivalently in terms of fold and f? I guess foldMap is some kind of composition of fold and f, but fold . f doesn't make sense.

Can foldMap f be defined equivalently in terms of foldl and f?

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
Tim
  • 1
  • 141
  • 372
  • 590
  • 10
    Please do a little research by looking at the source for `Data.Foldable` first, and make an *attempt* to either define `foldMap` in terms of `foldl`, or provide what you think is proof (or at least evidence) that you cannot do so. – chepner Jul 29 '19 at 17:31
  • 1
    What `fold` are you referring to? – chepner Jul 29 '19 at 17:32
  • 6
    @chepner Given the context of the question, I think it's pretty clearly [this `fold`](https://hackage.haskell.org/package/base-4.12.0.0/docs/Data-Foldable.html#v:fold) that's being referred to. (I fully agree with your comment suggesting more effort on the part of the asker, though.) – Daniel Wagner Jul 29 '19 at 17:39
  • I hope my answer helped, let me know if you need more info – developer_hatch Jul 30 '19 at 07:19

2 Answers2

4

Almost, but not quite.

myFoldMap
  :: (Foldable t, Functor t, Monoid m)
  => (a -> m) -> t a -> m
myFoldMap f = fold . fmap f

This idea is where foldMap gets its name, but it has a Functor constraint that can't be satisfied by types like Data.Set.Set.

As for foldr and foldl, you can get the right types, and the right behavior for finite containers, but not the right behavior for infinite containers. Consider what foldl does for

data Stream a = a :< Stream a
  deriving Foldable

and what foldr does for

data RStream a = RStream a :> a
  deriving Foldable

In each case, you'll end up with an infinite loop.

dfeuer
  • 48,079
  • 5
  • 63
  • 167
  • `fold` is defined using `foldMap`: https://hackage.haskell.org/package/base-4.12.0.0/docs/src/Data.Foldable.html#fold Wouldn't this lead to an infinite loop? – Niko Jul 29 '19 at 18:36
  • 1
    @Niko, that's a *default* definition. It works often enough to be useful, but it doesn't work for every container. – dfeuer Jul 29 '19 at 18:37
  • Thanks. (1) Is your way that requires the foldable also be a functor the only possible way for representing `foldMap` by `fold` and `f`? Is it necessary that the foldable also be a functor? (2) How do you define `foldMap f` equivalently in terms of `foldl` and `f`? – Tim Jul 29 '19 at 18:58
  • @Tim, (1) think about what you need to give `fold`, compared to what `foldMap` is given. What do you need to do to adapt one to the other? (2) Try writing `foldMap f = foldl _ _` in an instance and see what the compiler tells you. Can you see how to plug the holes? – dfeuer Jul 29 '19 at 19:11
  • In both (1) and (2), I guess your approach is trying to bridge them at the type level, and I am also concerned about whether the definitions are equivalent. In (1) furthermore, my question is whether your way that imposes the extra functor requirement is the only way. – Tim Jul 29 '19 at 19:13
  • @Tim, fold + map gives an equivalent (but slower) implementation. As I explained already, `foldl` can only do so in some situations. For (2), you're really going to have to try it yourself and see what you find if you want to learn something. – dfeuer Jul 29 '19 at 19:15
  • Thanks. I am unable to understand the part about foldr and foldl in your answer. First of all, I can't find out what `:>` and `:<` mean. – Tim Jul 29 '19 at 19:26
  • 1
    @Tim, they're data constructors I'm defining. I suspect it's time for to take a step back and work through some of the earlier chapters of a Haskell book. – dfeuer Jul 29 '19 at 19:58
  • What am I expected to step back to? In `data Stream a = a :< Stream a`, the part after `=` is supposed to be a sequence of constructors separated by `|`, so I guess you new type has only one constructor `a :< Stream a`. But I have never seen such a "convoluted" constructor in " the earlier chapters of a Haskell book". I am not sure what the constructor means, if it has some special keywords or predefined symbols, and what `:>` and `:<` in the constructor mean – Tim Jul 29 '19 at 20:01
  • @Tim, they're just infix. An operator that starts with a colon is a constructor, like `:` for lists. – dfeuer Jul 29 '19 at 23:19
  • @Tim, just one. That could also be written `data Stream a = (:<) a (Stream a)`. It represents a list that is definitely infinite. – dfeuer Jul 30 '19 at 00:44
2

If you carefully check the type of foldr and foldl you will see how easy could be:

look:

foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b

foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b

so... what can we do here... mmm, do you know flip?

flip :: (a -> b -> c) -> b -> a -> c

ok then:

foldMap' :: (Foldable t, Monoid m) => (a -> m) -> t a -> m
foldMap' f = foldl (flip (mappend . f)) mempty
developer_hatch
  • 15,898
  • 3
  • 42
  • 75