<div dir="ltr"><div dir="auto">Ok cool. These both make sense to me then.  and sound like a good idea!</div><div dir="auto"><br></div><div dir="auto">It would be nice to know what public instances would break as is with the change: and if they do, how many need the extra constraint david suggests on their instance.  As long as those are easy to rectify and we get such a nice asymptotic win, this sounds great! </div><div dir="auto"><br></div><div dir="auto">An idea I’ve mentioned before is that </div><div>a simple "fast" way to to approximate / see where things might be impacted is the following work flow:</div><div><br></div><div>>  cabal list --simple | awk '{print ($1)}' |  uniq | time xargs -P20  -n1 cabal get<br></div><div>and then grep around for uses of MonadFree to see what might be impacted by such a change</div><div><br></div><div>its a really simple way to evaluate an "over approximation"  in terms of usage of an interface, or namespace/syntax (by no means complete, esp since the above only pulls down the most recent version of every package), but also pretty zippy all things considered</div></div><div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Sat, Jul 17, 2021 at 10:20 AM Edward Kmett <<a href="mailto:ekmett@gmail.com" target="_blank">ekmett@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr"><br></div><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Sat, Jul 17, 2021 at 5:32 AM Carter Schonwald <<a href="mailto:carter.schonwald@gmail.com" target="_blank">carter.schonwald@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="auto">What about having the class head be </div><div dir="auto"><br></div><div dir="auto">Monad m, Functor f=> … MonadFree f m .. </div><div dir="auto">?</div></blockquote><div> </div><div>Requiring f to be a Functor would be too strong. Plenty of these are not.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="auto"></div><div dir="auto">Is the motivation here to have a more performant liftF?</div><div dir="auto"><br></div><div dir="auto">What are some examples of more efficient implementations for current instances and what’s the performance delta? </div></blockquote><div><br></div><div>Often the difference can be a walk of the entire structure. I'm not allergic to the idea of just adding the method to the class as proposed, it already has a superclass, so it is already a record internally, etc. </div></div></div><div dir="ltr"><div class="gmail_quote"><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Jul 16, 2021 at 6:53 PM David Feuer <<a href="mailto:david.feuer@gmail.com" target="_blank">david.feuer@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="auto">Another flavor would be to leave liftF alone and add a method that does the same thing with a different name. This would preserve performance characteristics for instances like FT, for situations where the current implementation is faster.</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Jul 16, 2021, 4:55 PM David Feuer <<a href="mailto:david.feuer@gmail.com" target="_blank">david.feuer@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="auto">We have<div dir="auto"><br></div><div dir="auto">class Monad m => MonadFree f m | m -> f where</div><div dir="auto">  wrap :: f (m a) -> m a</div><div dir="auto"><br></div><div dir="auto">liftF :: (Functor f, MonadFree f m) => f a -> m a</div><div dir="auto">liftF = wrap . fmap pure</div><div dir="auto"><br></div><div dir="auto">I propose we change this to</div><div dir="auto"><br></div><div dir="auto">class Monad m => MonadFree f m | m -> f where</div><div dir="auto">  wrap :: f (m a) -> m a</div><div dir="auto"><br></div><div dir="auto">  liftF :: f a -> m a</div><div dir="auto"><div dir="auto" style="font-family:sans-serif">  default liftF :: Functor f => f a -> m a</div><div dir="auto" style="font-family:sans-serif">  liftF = wrap . fmap pure</div><div dir="auto" style="font-family:sans-serif"><br></div><div dir="auto" style="font-family:sans-serif">and add a function</div><div dir="auto" style="font-family:sans-serif"><br></div><div dir="auto" style="font-family:sans-serif">defaultWrap :: MonadFree f m => f (m a) -> m a</div><div dir="auto" style="font-family:sans-serif">defaultWrap = join . liftF</div><div dir="auto" style="font-family:sans-serif"><br></div><div dir="auto" style="font-family:sans-serif">This change is not strictly backwards compatible. Some instances might, hypothetically, have to add a Functor constraint. For example, the classic Control.Monad.Free and Control.Monad.Trans.Free would need them. However, those instances already have (currently redundant) Functor constraints, so that doesn't seem like a big deal.</div><div dir="auto" style="font-family:sans-serif"><br></div><div dir="auto" style="font-family:sans-serif">An alternative would be to hew more strictly to backwards compatibility by placing a Functor f constraint on liftF. This seems a bit sad for "freer" instances that don't need it. For example, we have</div><div dir="auto" style="font-family:sans-serif"><br></div><div dir="auto"><div dir="auto"><font face="sans-serif">newtype FT f m a =</font> <span style="font-family:sans-serif">FT</span></div><div dir="auto"><span style="font-family:sans-serif">  {</span> <span style="font-family:sans-serif">runFT :: forall r. (a -> m r) -> (forall x. (x -> m r) -> f x -> m r) -> m r }</span></div><div style="font-family:sans-serif" dir="auto"><br></div><div style="font-family:sans-serif" dir="auto">for which</div><div style="font-family:sans-serif" dir="auto"><br></div><div style="font-family:sans-serif" dir="auto">liftF :: f a -> FT f m a</div><div style="font-family:sans-serif" dir="auto">liftF fa = FT $ \pur bndf -> bndf pur fa</div><div style="font-family:sans-serif" dir="auto"><br></div><div style="font-family:sans-serif" dir="auto">Pull request at <a href="https://github.com/ekmett/free/pull/208" rel="noreferrer" target="_blank">https://github.com/ekmett/free/pull/208</a></div></div></div></div>
</blockquote></div>
_______________________________________________<br>
Libraries mailing list<br>
<a href="mailto:Libraries@haskell.org" target="_blank">Libraries@haskell.org</a><br>
<a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries" rel="noreferrer" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries</a><br>
</blockquote></div></div>
_______________________________________________<br>
Libraries mailing list<br>
<a href="mailto:Libraries@haskell.org" target="_blank">Libraries@haskell.org</a><br>
<a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries" rel="noreferrer" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries</a><br>
</blockquote></div></div>
</blockquote></div></div>