
Friends Some of you will know that I've promised to give a talk about Edward's lens libraryhttp://hackage.haskell.org/package/lens at the Haskell Exchangehttp://skillsmatter.com/event/scala/haskell-exchange in London next Wednesday (9th). I did this to give everyone (including me) a break from GHC hackery, and also to force me to learn about this lens voodoo that everyone is twittering about. Edward generously gave me quite a bit of one-to-one attention last week (my hair is still standing on end), but this message is to ask your help too. Specifically, I'd like to give some compelling use-cases. If you are using the lens library yourself, could you spare a few minutes to tell me how you are using it? I expect to cover Lens and Traversal but not Prism. The use-case everyone starts with is nested records, but I'd like to go beyond that. The next levels seem to be: * Lenses as views of data that isn't "really there" e.g. regarding a record with rectangular coordinates as having polar coordinates too. * Lenses and Traversals that focus on elements of finite maps (Control.Lens.At) What else? I'm sure you are using them in all sorts of cool ways that I would never think of, and I'd love to know. Please don't tell me anything secret! And don't burn too many cycles on this...I don't want to waste your time, and I can always get back to you if I can't understand what you say. Sooner is better than later...Weds is coming. Simon "Edward's prophet" PJ

Simon Peyton-Jones
Friends
snip
The use-case everyone starts with is nested records, but I'd like to go beyond that. The next levels seem to be:
* Lenses as views of data that isn't "really there" e.g. regarding a record with rectangular coordinates as having polar coordinates too.
Along these lines, I've found lenses to be quite useful in providing a means of peering into and modifying packed binary data structures and bitfields. One example would be lines 50 - 100 of this module[1]. Cheers, - Ben [1] https://github.com/bgamari/hphoton/blob/master/hphoton-fpga-timetagger/HPhot...

Simon, On Thu, 2013-10-03 at 08:07 +0000, Simon Peyton-Jones wrote:
If you are using the lens library yourself, could you spare a few minutes to tell me how you are using it?
I'm not a heavy 'lens'-user (yet), and this might not be the most pretty use-case from a theoretic point of view, but anyway: I use 'lens' in Kontiki [1], my implementation of Raft [2], a fairly recent consensus protocol for distributed systems (think Paxos & multi-Paxos, Zookeeper,...). The Raft protocol description is fairly imperative ("When in state S, if you receive a message M, broadcast message M'(M) to all other nodes, append entry E(M) to your log, and update the state to S'(S)"), so in order to keep the code close to this description, I created a TransitionT monad transformer (where the underlying monad should, in some cases, provide access to the persisted log of the system, most likely requiring IO access, but this is abstracted over), which is basically RWST. The R environment gives access to system configuration (e.g. the set of nodes (or at least their names/IDs) part of the cluster), W is used to output/list Commands to be executed as part of a state transition, S gives access to the current state, and a transition should yield a new state (or the old one if e.g. a message is received which should be ignored in the current state). See [3] for an overview of the types involved. Finally, after this long introduction, the 'lens' part: thanks to the 'lens' operators, and my types involved in the TransitionT monad (specifically the R environment and S state) being lens'ified, accessing R & S becomes fairly unobtrusive and more imperative-looking (which makes sense when using RWS). As an example, in [4], you see some parts of the current (Candidate) state being accessed: currentTerm <- use cCurrentTerm votes <- use cVotes Not using 'lens', this would be something (OTOH) like currentTerm <- fmap _cCurrentTerm get which is less familiar from an imperative POV. Then also updating the current state 'in-place' (not for real, obviously): cVotes %= Set.insert sender And accessing the configuration (R) environment, e.g.: nodeId <- view configNodeId See other handler functions in that module, or in the Follower and Leader modules in the same directory, for more examples. Regards, Nicolas [1] https://github.com/NicolasT/kontiki [2] https://ramcloud.stanford.edu/wiki/download/attachments/11370504/raft.pdf [3] https://github.com/NicolasT/kontiki/blob/master/src/Network/Kontiki/Types.hs [4] https://github.com/NicolasT/kontiki/blob/master/src/Network/Kontiki/Raft/Can...

The thing that really clicked lenses for me was reading through some of Twan van Laarhoven's slides where he presented an isomorphic definition of lenses. Googling reveals he actually has a very nice blog entry about this now. http://twanvl.nl/blog/haskell/isomorphism-lenses To strip out the essential element. A lens is -- Isomorphisms/bijections between type @a@ and @b@ data Iso a b = Iso { fw :: a -> b, bw :: b -> a } -- Lenses with a data wrapper, in practice you might want to unpack the Iso type data Lens a b = forall r. Lens (Iso a (b,r)) That is, a lense is two functions 1 - fw : data -> (element, residue data) [ this takes apart the data ] 2 - bw : (element, residue data) -> data [ this puts it back together ] such that they are an isomorphism (i.e., if you take it apart and then put it back together you get the same thing). fw . bw = bw . fw = id This made sense to me pretty much as soon as I encountered it. This was certainly not the case with the other. Cheers! -Tyson PS: I would really encourage looking at the blog post. It is a relatively easy read and well worth it.

I rarely use lens without using any Prisms so this is slightly out of scope, but I absolutely love both lens-aeson and my own package hexpat-lens for diving deeply into nested data structures. Here's a line from a toy web scraper I wrote a few weeks ago using hexpat-lens. p ^.. _HTML' . to allNodes . traverse . named "a" . traverse . ix "href" . filtered isLocal . to trimSpaces The _HTML' bit is a parser Prism based loosely on lens-aeson's _JSON Prism and allNodes uses lens' built-in generic traversal machinery. Specifically, it's a synonym for universe which uses the Plated instance I wrote since there's an obvious concept of the child of an XML node. You could do it even more lens-ily by using universeOf and passing it a traversal into the children. Anyway, that's all the "extra" stuff used here. The essence of this code is to dive into all of the anchors in a page, pull their href (if it exists), remove any non-local hrefs, and then canonicalize the final string. The (^..) runs the traversal returning a list of the results. The clever part I want to share is the use of ix here enabled by the Ixed instance for UNode which lets me treat the implicit attribute dictionary using the generic lens machinery. Also in XML processing, I've begun to look into the bidirectional programming XML pickler libraries. I'm not sure which will work best for me right now, but by writing a few combinators like `xpWrapIso` I'm able to integrate the entire Iso machinery of lens (of which there is a lot) to bootstrap the parser/printers I'm writing. Hopefully this gives a good, if brief, glimpse into some practical lens usage I've had recently. — Joseph
participants (5)
-
Ben Gamari
-
Joseph Abrahamson
-
Nicolas Trangez
-
Simon Peyton-Jones
-
Tyson Whitehead