<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">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 class="gmail-Apple-interchange-newline"></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><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>