<div dir="auto"><div>I've previously suggested similar things, like:<div dir="auto"><br></div><div dir="auto"><span style="font-family:sans-serif;font-size:12.8px">allA :: (Applicative f, Foldable t) => (a -> f Bool) -> t a -> f Bool</span><br style="font-family:sans-serif;font-size:12.8px"><span style="font-family:sans-serif;font-size:12.8px">allA f = fmap getAll . getAp . foldMap (Ap . fmap All . f)</span></div><br><span style="font-family:sans-serif">I think such functions are very convenient.</span><br><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, 8 May 2019, 1:37 pm David Feuer, <<a href="mailto:david.feuer@gmail.com">david.feuer@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto"><div>My second to last comment was potentially non-optimal in unusual cases. If fmap is sufficiently expensive for the functor in question, and f is not id, then you might want to use</div><div dir="auto"><br></div><div dir="auto">   import Data.Functor.Coyoneda</div><div dir="auto"><br></div><div dir="auto">   lowerCoyoneda . getAp . foldMap (Ap . fmap f . liftCoyoneda . g)</div><div dir="auto"><br></div><div dir="auto">This is pretty similar to the composition of foldMap and traverse, but it doesn't have a Traversable constraint.</div><div dir="auto"><br><div class="gmail_quote" dir="auto"><div dir="ltr" class="gmail_attr">On Tue, May 7, 2019, 10:59 PM David Feuer <<a href="mailto:david.feuer@gmail.com" rel="noreferrer noreferrer" target="_blank">david.feuer@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto"><div>TLDR: if you ever see anything that looks like<div dir="auto"><br></div><div dir="auto">  fmap (foldMap f) . traverse g</div><div dir="auto"><br></div><div dir="auto">then you should generally rewrite it to</div><div dir="auto"><br></div><div dir="auto">  getAp . foldMap (Ap . fmap f . g)</div><div dir="auto"><br></div>In this case, f = id, so you just need</div><div dir="auto"><br></div><div dir="auto">  getAp . foldMap (Ap . g)<br><br><div class="gmail_quote" dir="auto"><div dir="ltr" class="gmail_attr">On Tue, May 7, 2019, 10:49 PM David Feuer <<a href="mailto:david.feuer@gmail.com" rel="noreferrer noreferrer noreferrer" target="_blank">david.feuer@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto"><div><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, May 7, 2019, 9:57 PM Vanessa McHale <<a href="mailto:vanessa.mchale@iohk.io" rel="noreferrer noreferrer noreferrer noreferrer" target="_blank">vanessa.mchale@iohk.io</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">It's relatively easy to define foldMapA, viz.<br>
<br>
foldMapA ::  (Monoid b, Traversable t, Applicative f) => (a -> f b) -> t<br>
a -> f b<br>
foldMapA = (fmap fold .) . traverse<br></blockquote></div></div><div dir="auto"><br></div><div dir="auto">That's a bit hard for me to read. Let's rewrite it a bit:</div><div dir="auto"><br></div><div dir="auto">foldMapA f = fmap fold . traverse f</div><div dir="auto"><br></div><div dir="auto">Looking at it more plainly, I can see that this traverses the container with f, producing a bunch of values, then maps under the functor to fold them. That smells funny. Let's fix it.</div><div dir="auto"><br></div><div dir="auto">  fold</div><div dir="auto">    :: (Foldable f, Monoid a)</div><div dir="auto">    => f a -> a</div><div dir="auto">  fold = foldMap id</div><div dir="auto"><br></div><div dir="auto">  foldMapDefault</div><div dir="auto">    :: (Traversable t, Monoid m)</div><div dir="auto">    => (a -> m) -> t a -> m</div><div dir="auto">  foldMapDefault f = getConst . traverse (Const . f)</div><div dir="auto"><br></div><div dir="auto">so</div><div dir="auto"><br></div><div dir="auto"><span style="font-family:sans-serif">  foldMapA f = fmap (getConst . traverse Const) . traverse f</span><br></div><div dir="auto"><span style="font-family:sans-serif"><br></span></div><div dir="auto"><font face="sans-serif">By the functor composition law, we can write</font></div><div dir="auto"><font face="sans-serif"><br></font></div><div dir="auto"><div dir="auto" style="font-family:sans-serif">  foldMapA f = fmap getConst . fmap (traverse Const) . traverse f<br></div><br></div><div dir="auto">By the traversable composition law,</div><div dir="auto"><br></div><div dir="auto">  foldMapA f = fmap getConst . getCompose . traverse (Compose . fmap Const . f)<br></div><div dir="auto"><br></div><div dir="auto">This isn't looking so hot yet, but bear with me. fmap getConst doesn't actually do anything (it's operationally the same as fmap id = id), so we can ignore it). The functor we're traversing in is</div><div dir="auto"><br></div><div dir="auto">  Compose f (Const b) (t x)<br></div><div dir="auto"><br></div><div dir="auto">where x can be anything. How does this functor behave?</div><div dir="auto"><br></div><div dir="auto">  pure a</div><div dir="auto">    = Compose (pure (pure a))</div><div dir="auto">    = Compose (pure (Const mempty))</div><div dir="auto"><br></div><div dir="auto">  liftA2 f (Compose x) (Compose y)</div><div dir="auto">    = Compose (liftA2 (liftA2 f) x y)</div><div dir="auto">    = Compose (liftA2 (\(Const p) (Const q) -> p <> q) x y)</div><div dir="auto"><br></div><div dir="auto">Whew! There are a lot of newtype wrappers, but let's ignore them. Does this Applicative instance look familiar? It should. It's operationally the same as the Monoid instance for Data.Monoid.Ap! So we can weaken Traversable to Foldable, and write</div><div dir="auto"><br></div><div dir="auto"><span style="font-family:sans-serif">    foldMapA</span></div><div dir="auto"><span style="font-family:sans-serif">      :: (Monoid b, Foldable t, Applicative f)</span></div><div dir="auto"><span style="font-family:sans-serif">      => (a -> f b) -> t a</span><span style="font-family:sans-serif"> -> f b</span><br style="font-family:sans-serif"><span style="font-family:sans-serif">    foldMapA f = getAp . foldMap (Ap . f)</span><br></div><div dir="auto"><span style="font-family:sans-serif"><br></span></div><div dir="auto"><span style="font-family:sans-serif">But now it's so simple I'm not sure we need to define it anymore.</span></div><div dir="auto"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
</blockquote></div></div></div>
</blockquote></div></div></div>
</blockquote></div></div></div>
_______________________________________________<br>
Libraries mailing list<br>
<a href="mailto:Libraries@haskell.org" target="_blank" rel="noreferrer">Libraries@haskell.org</a><br>
<a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries" rel="noreferrer noreferrer" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries</a><br>
</blockquote></div></div></div>