Discussion: reconsider lens-like exports from containers

Way back when, Shachaf Ben-Kiki suggested an efficient implementation of `at` for Data.Map in https://mail.haskell.org/pipermail/libraries/2013-May/019761.html but that was never approved for inclusion. I believe I've come up with a somewhat nasty but efficient implementation of `ix` for Data.Sequence (hand-specialized and hand-unboxed), based on the code for `adjust`. See https://gist.github.com/treeowl/b80c2c490563765fc7881be30f3dba24 lens has continued to grow in popularity, so I think the time has probably come to talk again about adding `at` for Data.Map, and to talk about adding `ix` for Data.Sequence. Note: for consistency with the rest of the Data.Sequence API, `ix` would be named `adjustA`, and would have its first two arguments flipped. David Feuer

Hello, I don't feel qualified to take a stance on this, but since you did make a comment about "deafening silence" earlier on an unrelated issue, then, if this `adjustA` doesn't depend on any particular Lens library, and it's more efficient than any hand-rolled solution, then why not? Best regards, Marcin Mrotek

On Tue, Apr 26, 2016, at 15:03, David Feuer wrote:
Way back when, Shachaf Ben-Kiki suggested an efficient implementation of `at` for Data.Map in https://mail.haskell.org/pipermail/libraries/2013-May/019761.html but that was never approved for inclusion.
Funny thing, I just tried doing that not to long ago with `at`: https://github.com/haskell/containers/pull/192 In the end, the results were mixed. It was a small optimization in some situations, and a moderate pessimization in others (esp. when the Functor becomes too complex for GHC to optimize). -- RF

Right you are. Ugh. I'll need to rethink this.
On Apr 27, 2016 3:19 AM,
On Tue, Apr 26, 2016, at 15:03, David Feuer wrote:
Way back when, Shachaf Ben-Kiki suggested an efficient implementation of `at` for Data.Map in https://mail.haskell.org/pipermail/libraries/2013-May/019761.html but that was never approved for inclusion.
Funny thing, I just tried doing that not to long ago with `at`:
https://github.com/haskell/containers/pull/192
In the end, the results were mixed. It was a small optimization in some situations, and a moderate pessimization in others (esp. when the Functor becomes too complex for GHC to optimize).
-- RF

For cases were the Functor winds up particularly complicated or won't
be known at compile time so the inlining can't help, it turns out you
can usually work around this with the 'fusing' combinator from the
lens library. This works around the repeated stacks of `fmap` that get
built up otherwise, transforming everything into one gigantic fmap all
in one go.
There is a similar `confusing` combinator for working with traversals.
The implementation lives up to the name.
-Edward
On Wed, Apr 27, 2016 at 5:19 PM,
On Tue, Apr 26, 2016, at 15:03, David Feuer wrote:
Way back when, Shachaf Ben-Kiki suggested an efficient implementation of `at` for Data.Map in https://mail.haskell.org/pipermail/libraries/2013-May/019761.html but that was never approved for inclusion.
Funny thing, I just tried doing that not to long ago with `at`:
https://github.com/haskell/containers/pull/192
In the end, the results were mixed. It was a small optimization in some situations, and a moderate pessimization in others (esp. when the Functor becomes too complex for GHC to optimize).
-- RF _______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

I was thinking switching to CPS might help, passing the context down on the
way to the leaf, so the tree is built "inside" the functor. This is pretty
easy for nodes and digits, but I'm struggling with the polymorphic
recursion in the spine right now. I think I'll probably figure it out
eventually.
On Apr 27, 2016 6:12 PM, "Edward Kmett"
For cases were the Functor winds up particularly complicated or won't be known at compile time so the inlining can't help, it turns out you can usually work around this with the 'fusing' combinator from the lens library. This works around the repeated stacks of `fmap` that get built up otherwise, transforming everything into one gigantic fmap all in one go.
There is a similar `confusing` combinator for working with traversals. The implementation lives up to the name.
-Edward
On Wed, Apr 27, 2016 at 5:19 PM,
wrote: On Tue, Apr 26, 2016, at 15:03, David Feuer wrote:
Way back when, Shachaf Ben-Kiki suggested an efficient implementation of `at` for Data.Map in https://mail.haskell.org/pipermail/libraries/2013-May/019761.html but that was never approved for inclusion.
Funny thing, I just tried doing that not to long ago with `at`:
https://github.com/haskell/containers/pull/192
In the end, the results were mixed. It was a small optimization in some situations, and a moderate pessimization in others (esp. when the Functor becomes too complex for GHC to optimize).
-- RF _______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

That transformation is effectively what 'fusing' does. It CPSes (er..
Yonedas, actually) the functor `f` as forall r. (a -> r) -> f r, and
accumulates the changes by composing in more functions, so that it can
all be discharged with one fmap. You should be able to achieve the
same result by hand with a manual worker/wrapper transformation.
-Edward
On Thu, Apr 28, 2016 at 8:20 AM, David Feuer
I was thinking switching to CPS might help, passing the context down on the way to the leaf, so the tree is built "inside" the functor. This is pretty easy for nodes and digits, but I'm struggling with the polymorphic recursion in the spine right now. I think I'll probably figure it out eventually.
On Apr 27, 2016 6:12 PM, "Edward Kmett"
wrote: For cases were the Functor winds up particularly complicated or won't be known at compile time so the inlining can't help, it turns out you can usually work around this with the 'fusing' combinator from the lens library. This works around the repeated stacks of `fmap` that get built up otherwise, transforming everything into one gigantic fmap all in one go.
There is a similar `confusing` combinator for working with traversals. The implementation lives up to the name.
-Edward
On Wed, Apr 27, 2016 at 5:19 PM,
wrote: On Tue, Apr 26, 2016, at 15:03, David Feuer wrote:
Way back when, Shachaf Ben-Kiki suggested an efficient implementation of `at` for Data.Map in https://mail.haskell.org/pipermail/libraries/2013-May/019761.html but that was never approved for inclusion.
Funny thing, I just tried doing that not to long ago with `at`:
https://github.com/haskell/containers/pull/192
In the end, the results were mixed. It was a small optimization in some situations, and a moderate pessimization in others (esp. when the Functor becomes too complex for GHC to optimize).
-- RF _______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

Using Yoneda greatly improved performance for Identity, and raised the
performance for [] a little above that of the "fake" version lens
currently uses. But the performance for simply viewing an element is
awful (it takes about twice as long as `index`), and I'm beginning to
doubt there's any solution that will get the (small) speed-up in some
cases without getting a (large) slow-down elsewhere. Oh well.
On Wed, Apr 27, 2016 at 6:39 PM, Edward Kmett
That transformation is effectively what 'fusing' does. It CPSes (er.. Yonedas, actually) the functor `f` as forall r. (a -> r) -> f r, and accumulates the changes by composing in more functions, so that it can all be discharged with one fmap. You should be able to achieve the same result by hand with a manual worker/wrapper transformation.
-Edward
On Thu, Apr 28, 2016 at 8:20 AM, David Feuer
wrote: I was thinking switching to CPS might help, passing the context down on the way to the leaf, so the tree is built "inside" the functor. This is pretty easy for nodes and digits, but I'm struggling with the polymorphic recursion in the spine right now. I think I'll probably figure it out eventually.
On Apr 27, 2016 6:12 PM, "Edward Kmett"
wrote: For cases were the Functor winds up particularly complicated or won't be known at compile time so the inlining can't help, it turns out you can usually work around this with the 'fusing' combinator from the lens library. This works around the repeated stacks of `fmap` that get built up otherwise, transforming everything into one gigantic fmap all in one go.
There is a similar `confusing` combinator for working with traversals. The implementation lives up to the name.
-Edward
On Wed, Apr 27, 2016 at 5:19 PM,
wrote: On Tue, Apr 26, 2016, at 15:03, David Feuer wrote:
Way back when, Shachaf Ben-Kiki suggested an efficient implementation of `at` for Data.Map in https://mail.haskell.org/pipermail/libraries/2013-May/019761.html but that was never approved for inclusion.
Funny thing, I just tried doing that not to long ago with `at`:
https://github.com/haskell/containers/pull/192
In the end, the results were mixed. It was a small optimization in some situations, and a moderate pessimization in others (esp. when the Functor becomes too complex for GHC to optimize).
-- RF _______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
participants (4)
-
David Feuer
-
Edward Kmett
-
Marcin Mrotek
-
rf@rufflewind.com