5 ms·
Lenses let you do some amazing things, but I think most of their existence is just thanks to how truly horrible (nested) record field access and updates were.
by the_duke 4y ago
Lenses let you do some amazing things, but I think most of their existence is just thanks to how truly horrible (nested) record field access and updates were.
This is a lot better now with record dot syntax. [1]
[1] https://ghc-proposals.readthedocs.io/en/latest/proposals/0282-record-dot-syntax.html#record-dot-syntax https://ghc-proposals.readthedocs.io/en/latest/proposals/028...
- ParetoOptimal 4y ago> Lenses let you do some amazing things, but I think most of their existence is just thanks to how truly horrible (nested) record field access and updates were. Only for the most basic uses. Architecting programs as folds or traversals can be powerful. One simple example of lenses i can think of being useful for more than record access is: > sumOf (folded . folded) [Just 1, Just 2] 3 More are in this presentation: https://m.youtube.com/watch?v=QZy4Yml3LTY https://m.youtube.com/watch?v=QZy4Yml3LTY
- WJW 4y agoNot to be a lens hater, but I would definitely flag it in PR review if someone came up with that instead of something like this: > sum $ map (fromMaybe 0) <some list of Maybe Int> Possibly with a different default value for Nothings. A lot of the optics libraries seem to focus a lot on making the general case as easy as possible while overcomplicating the specific case. `sumOf (folded . folded)` does have some advantages in working for lists of other types but I question how often you would reuse such a function for different types the first place. It just doesn't come up all too often in my own code, perhaps it is different elsewhere.
- ParetoOptimal 4y ago> `sumOf (folded . folded)` does have some advantages in working for lists of other types but I question how often you would reuse such a function for different types the first place. The common refactor here would be to Either: > sumOf (folded . folded) [Right 1, Right 2] 3 I don't like the "unwrap the Maybe" or "get rid of the pesky monad in my way" intuition that fromMaybe and catMaybes give beginners. > A lot of the optics libraries seem to focus a lot on making the general case as easy as possible while overcomplicating the specific case. I kind of agree with this, but contend the universality of a single powerful and composable lens syntax simplifies things more overall even if it makes a single use site more complicated.
- ParetoOptimal 4y ago> `sumOf (folded . folded)` does have some advantages in working for lists of other types but I question how often you would reuse such a function for different types the first place. Just remembered another refactor that comes up a lot for me: Refactoring `[a]` to `NonEmpty a`. A lot of times this tightens your code up, but i find if the call chain is monomorphic to list most won't bother with the refactor. So I like lens for pushing away from that level of monomorphism that is resistant to better architecture.
- unhammer 4y agoI prefer non-powerful functions for trivial problems: > sum $ map (fromMaybe 0) [Just 1, Just 2] 3
- lucasdicioccio 4y agoI wouldn't call that trivial but "common", and for these cases we could even use something like catMaybes: > sum . catMaybes Lenses (imho) shine when you have to write data-extractors for arbitrary-complex and ill-documented APIs with corner cases or things like HTML scrapping. The beauty of lenses is that you get one composable language across libraries. For instance, if your HTTP-library has lenses and your XML-library has lenses, you can write things like safely composing a getElementsByTagName with some XML-parsing and data extractions: > response ^.. responseBody . xml . folding universe . named (only "p") . text and the bonus is that if you need to filter, you can do that with a similar mechanism (e.g., filtering based on some html meta-tag) overall it feels like SQL-for-arbitrary-structures: dense but powerful
- ParetoOptimal 4y agoI prefer a general polymorphic solution to optimize for global simplicityand consistency rather than lots of different ad-hoc simpler solutions that are more complex and/or less composable altogether.
- the_duke 4y agoIt can be powerful, but it also makes code a lot more complicated and confusing. The focus on fancy type level abstractions is why Haskell is so interesting, but it is also one of the reasons I don't use Haskell in a business environment. Everything is just so complicated, and every library does things somewhat differently.
- chowells 4y agoLenses are not fancy or complicated. They require no language extensions to create or use at all. Heck, it require no libraries beyond base to create lenses for others to use. There's a bit to learn, but there's nothing fancy. It's just a matter of applying a simple pattern repeatedly. (Or doing some software engineering and letting a library do the repetition for you.)
- jerf 4y ago"Architecting programs as folds or traversals can be powerful." This is my own idiosyncratic view but lately I've been fiddling with the proposition that the defining characteristic of functional programming languages is the definition and pervasive utilization of recursion schemes via composition as the primary organizational method for code. That is to say, such programs do not just borrow a few recursion schemes here or there (like chaining a map with a filter and calling it a "functional program"), but that the entire architecture is oriented around operating on data via such recursion schemes, stacked on top of each other. So many of the previous touchstones keep getting moved into non-functional languages, like "functions as first-class citizens" (almost everything has this now) and "immutability" (less common, but common enough we can say with confidence now that having immutable values does not turn a language "functional"), but the destination languages remain quite distinct from something like Haskell. From that point of view, lens is a development you'd expect any such language to eventually come up with and make extensive use of. It isn't the only way to compose recursion schemes together, but it's certainly one of the basic tools. (An interesting element of this particular heterodox view is that this enables one to imagine a "pure functional language" that is not based on total immutability, though whether that's a good idea is another question.)
- aranchelk 4y agoA similar statement could be made about monads. Originally used to implement IO in Haskell because it’s a lazy pure functional language, they’re largely unnecessary in strictly evaluated languages. Monads are now of course seen by Haskellers as being very useful in many different use cases beyond the original motivation. IO in PureScript, which I’d describe as strictly evaluated Haskell, is still implemented using monads. The biggest benefit of this (as one might expect) is forcing the separation of pure and impure code, but a cool byproduct is asynchronous IO is also implemented in a monad. Various functions are available to launch async from synchronous IO and lift synchronous functions into async. The ergonomics of mixing sync and async are better than any other language I’ve used. So theres an interesting question: once you have dot syntax, are there reasons you’d still want lenses? I’ve come up with two. First, it is nice to use “over” (%~) to avoid specifying a location in a data structure twice (first to read it and apply a function to the read value, second to create a new data structure with the read value replaced with the output of the function. The deeper the data structure, the bigger the benefit. The second case is writing functions that take lenses as an input and operate generically with larger data structures without knowing where in the larger data structure the values of interest reside ahead of time.
- prionassembly 4y agoI started using monads in Python as sort of a gimmick / something to add flavor to a boring project (I was guessing in a final form we'd keep Result types and throw away most other things) but by now they're a boon to productivity and easy to read in fluent notation. Plus they're easy to implement from scratch if you're dependency-phobic (on the rather rickety selection of monad libraries out there, too).
- yccs27 4y agoWhat monad library do you use? When I tried using monads in Python a while ago it felt like Python just wasn't made for monadic programming.
- prionassembly 4y ago
- spopejoy 4y agoPerhaps they were born of necessity but now they are a strictly better solution for computing on members than any other solution or language feature. Record dot syntax is very unappealing. Would way prefer automatic lenses, or just some principled way to qualify using the constructor or equivalent. And take your hands off my compose operator tyvm!