Open luc-tielen opened 1 year ago
I think the main issue is that we're very reliant on two things: a) the lens
classy lenses and b) the lens
auto-generation machinery.
a) is important because there is a lot of name reuse in the LSP spec. We really need overloaded field accessors, and with lens that means using the classy lenses AFAIK. b) is important because there are so many types, there is no way we could write them by hand.
Maybe once I finally get https://github.com/haskell/lsp/pull/458 over the line we could consider writing our own lens generation machinery... but that seems like a lot of work :/ Alternatively I guess something like generic-lens
might work. Any other ideas?
I have to admit I'm not that experienced with lenses and such. :sweat_smile: I found this recent thread on reddit: https://www.reddit.com/r/haskell/comments/z0czfc/the_modern_lens_setup_genericlens/ Maybe optics-core provides enough functionality for what you need? (See one of the replies.)
In any particularly big development you'll have lens
. Having microlens
will only add microlens
.
Consider the install plan for haskell-language-server-1.7.0.0
with GHC-9.0.2.
microlens
now!hls-plugin-api
depends on lens-aeson
and thus lens
lsp-types
depends on lens
I'm actually somewhat surprised that there aren't more dependencies on lens
.
In the big picture lens
is a small library. E.g. profunctors
and semigroupoids
are needed by stm-containers
. free
(which also needs profunctors
and semigroupoids
) is used by ghc-exactprint
. So "big" kmett's lens
dependencies
are already there. And then vector
, unordered-containers
, ... are depended upon other stuff, e.g. aeson
.
TL;DR if you change lens
to microlens
in one place, you just add microlens
to the mix.
EDIT: generic-lens
is slow. Compile-time is slow at use sites, as well as there is no performance guarantees. TH generated lenses are more predicatable in both regards.
I'm considering switching to generic-lens
. Reasons:
lsp-types
RecordDotSyntax
for those who want simple usagelsp-types
I don't know how bad this would be downtream, though.
Trying it out it seems that https://github.com/kcsongor/generic-lens/issues/96 would be annoying for us.
Lets us drop the creation and compilation of hundreds of lens declarations from lsp-types
But then you'll do a lot of generics evaluation at compile time at each use site (and GHC is slow to do that). It's far from clear it is a net win (especially if lsp-types
is relatively more stable part of codebase).
Yes, I agree the compilation time is maybe a wash. Honestly the thing I find most pleasing is being able to get away from prefixing all the fields with _
...
With NoFieldSelectors
you can have lens
and no _
prefix (using custom LensRules
and makeLensesWith
):
{-# LANGUAGE NoFieldSelectors, TemplateHaskell #-}
import Control.Lens
import Language.Haskell.TH (mkName, nameBase)
data Foo = MkFoo { int :: Int, char :: Char} deriving Show
$(let namer _ty _ns n = [TopName $ mkName $ nameBase n] -- identity namer
rules = lensRules & lensField .~ namer
in makeLensesWith rules ''Foo)
main :: IO ()
main = do
print $ (MkFoo 21 'x')
& char .~ 'y'
& int %~ (* 2)
Tested with GHC-9.2.7.
FYI, generic lenses and prisms from optics-core
are well-optimized for compile time evaluation (much better than generic-lens
, some measurements are available here) and have better ergonomics.
As for the runtime performance, generic lenses at least for pure products always (well, up to 100 fields at minimum) optimize well (this is ensured by tests from https://gitlab.haskell.org/ghc/ghc/-/merge_requests/2965), for sums it's more restrictive (more details are in the MR if you're interested).
A long time ago I've switched a large codebase with about 3k use sites of lenses from TH generated optics to generic optics and compile times with optimizations were pretty much the same (about 15% slower without optimizations).
Hi,
I saw that
lsp
has a dependency onlens
, which is a fairly large dependency. Would it be possible to swap it out for an alternative such as overloaded dot syntax ormicrolens
? I'm asking this because my compiler's build time almost doubled just including this library.Are there any things blocking this? Or is there another reason behind it?