<div dir="ltr"><div style>I find generalizing even more with &quot;at&quot; or &quot;alterF&quot; a very interesting suggestion and I&#39;m fine with either title. I however was not able to trace any practical use of it, because in my imagination the original proposal covered all scenarios, so it&#39;d be helpful to see some examples. Also since the performance turned out to be such an intricate issue in this case I think it is worth benchmarking both the functorial and the simple version. But either way I like the idea.</div>
<div style><br></div><div style>I also want to highlight the expressed idea that either version of this function should make it into the library no matter whether we&#39;re able to come up with an efficient implementation, since those functions also provide another important benefit by abstracting over a common pattern, thus simplifying the client code.</div>
<div><br></div><div>Schachaf, concerning your implementation. Great! It looks like a beginning of an implementation process. What do you think about posting it with the benchmark as a branch of your fork of &quot;containers&quot; project on GitHub? This way other participants will be able to fork from you and continue on with experiments, so it&#39;ll be easier for us to manage code and to keep in sync. </div>
</div><div class="gmail_extra"><br><br><div class="gmail_quote">2013/5/1 Shachaf Ben-Kiki <span dir="ltr">&lt;<a href="mailto:shachaf@gmail.com" target="_blank">shachaf@gmail.com</a>&gt;</span><br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="im">On Tue, Apr 30, 2013 at 8:20 AM, Milan Straka &lt;<a href="mailto:fox@ucw.cz">fox@ucw.cz</a>&gt; wrote:<br>
&gt; Hi all,<br>
&gt;<br>
&gt;&gt; -----Original message-----<br>
&gt;&gt; From: Nikita Volkov &lt;<a href="mailto:nikita.y.volkov@gmail.com">nikita.y.volkov@gmail.com</a>&gt;<br>
&gt;&gt; Sent: 30 Apr 2013, 17:18<br>
&gt;&gt;<br>
&gt;&gt; Because of the above I have very often found myself in requirement for the following function:<br>
&gt;&gt;<br>
&gt;&gt;    withItem ::<br>
&gt;&gt;      (Ord k) =&gt;<br>
&gt;&gt;      k -&gt;<br>
&gt;&gt;      (Maybe i -&gt; (r, Maybe i)) -&gt;<br>
&gt;&gt;      Map k i -&gt; (r, Map k i)<br>
&gt;&gt;    withItem k f m =<br>
&gt;&gt;      let<br>
&gt;&gt;        item = Map.lookup k m<br>
&gt;&gt;        (r, item&#39;) = f item<br>
&gt;&gt;        m&#39; = Map.update (const item&#39;) k m<br>
&gt;&gt;      in (r, m&#39;)<br>
&gt;<br>
&gt; last time we talked about adding<br>
&gt;   lens :: k -&gt; Map k a -&gt; (Maybe a -&gt; Map k a, Maybe a)<br>
&gt; the performance of the direct implementation was actually worse than<br>
&gt; using lookup+insert or such, see the thread<br>
&gt; <a href="http://www.haskell.org/pipermail/libraries/2012-January/017423.html" target="_blank">http://www.haskell.org/pipermail/libraries/2012-January/017423.html</a><br>
&gt; and the benchmark results at<br>
&gt; <a href="http://www.haskell.org/pipermail/libraries/2012-January/017435.html" target="_blank">http://www.haskell.org/pipermail/libraries/2012-January/017435.html</a><br>
&gt;<br>
<br>
</div>If this is a good API, and the direct implementation is slower than an<br>
indirect implementation in terms of lookup+insert+delete, then the<br>
indirect implementation should be exported. Keep in mind that this<br>
operation is just `alterM` (except generalized to Functor --<br>
`alterF`?).<br>
<br>
However: I just wrote a quick direct version:<br>
<br>
    alterF :: (Ord k, Functor f) =&gt; k -&gt; (Maybe a -&gt; f (Maybe a)) -&gt;<br>
Map k a -&gt; f (Map k a)<br>
    STRICT_1_OF_2(alterF)<br>
    alterF k f = go<br>
      where<br>
        go Tip = maybe Tip (singleton k) &lt;$&gt; f Nothing<br>
        go (Bin sx kx x l r) =<br>
          case compare k kx of<br>
            LT -&gt; (\l&#39; -&gt; balance kx x l&#39; r) &lt;$&gt; go l<br>
            GT -&gt; (\r&#39; -&gt; balance kx x l r&#39;) &lt;$&gt; go r<br>
            EQ -&gt; maybe (glue l r) (\x&#39; -&gt; Bin sx kx x&#39; l r) &lt;$&gt; f (Just x)<br>
<br>
And benchmarked lookup-via-alterF, insert-via-alterF, etc. -- they<br>
come out much slower. However, if I add an INLINE pragma or SPECIALIZE<br>
pragmas for common/relevant functors (e.g. Const r, Identity, (r,)),<br>
then they come out almost the same speed as the primitive function.<br>
<br>
I don&#39;t think INLINE is necessarily bad for this function. (I don&#39;t<br>
like the idea of using SPECIALIZE here because I don&#39;t think e.g.<br>
Identity should have special privileges over some other newtype with<br>
the same Functor instance.) So maybe the direct implementation should<br>
be reconsidered. I can do a more thorough benchmark later if people<br>
are interested.<br>
<div class="im"><br>
&gt;<br>
&gt; I am also a bit worried whether withItem is the &quot;right&quot; general<br>
&gt; function. For example Shachaf Ben-Kiki mentions the<br>
&gt;   at :: (Ord k, Functor f) =&gt; k -&gt; (Maybe i -&gt; f (Maybe i)) -&gt; Map k i -&gt; f (Map k i)<br>
&gt; from the lens package in other mail, but maybe there are others.<br>
&gt;<br>
<br>
</div>I think that alterF almost certainly *a* right function -- it&#39;s just a<br>
monadic/functorial version of `alter`, which is the most general<br>
&quot;simple&quot; updating function. Possibly there should be others too, but<br>
this one is useful and general. Although it needs a better name. :-)<br>
<br>
(Note that e.g.<br>
    adjustF :: (Ord k, Applicative f) =&gt; k -&gt; (a -&gt; f a) -&gt; M.Map k a<br>
-&gt; f (M.Map k a)<br>
can just be<br>
    \k -&gt; alterF k . traverse<br>
just as with alter/adjust.<br>
<div class="HOEnZb"><div class="h5">)<br>
<br>
&gt;<br>
&gt;&gt;    1. Implement an efficient version of &quot;withItem&quot; for lazy and strict versions of &quot;Map&quot; and &quot;IntMap&quot;.<br>
&gt;<br>
&gt; Maybe we will need a benchmark to see whether withItem is really faster<br>
&gt; than combination of lookup+update.<br>
&gt;<br>
&gt;&gt;    3. Begin the deprecation process of the following functions: insertWith, insertWithKey, insertLookupWithKey, adjust, adjustWithKey, update, updateWithKey, updateLookupWithKey, alter.<br>
&gt;<br>
&gt; I am against deprecating insertWith, insertWithKey, updateWithKey,<br>
&gt; updateWithKey, because they are useful.<br>
&gt;<br>
&gt; I am against deprecating adjust, adjustWithKey and alter, mostly because<br>
&gt; of compatibility reasons, although I agree that their name is not<br>
&gt; descriptive.<br>
&gt;<br>
&gt; I am indifferent about insertLookupWithKey and updateLookupWithKey. It<br>
&gt; would be nice to show that their implementation is really faster than<br>
&gt; lookup+insert / lookup+update combo.<br>
&gt;<br>
<br>
</div></div><span class="HOEnZb"><font color="#888888">    Shachaf<br>
</font></span></blockquote></div><br></div>