Sort of. It has the Focus library. It would allow you to say something like:

Focus.update (a => b) ((+) 3) test

...to add three to test.a.b . It has two drawbacks that spring to mind. The first is that you have to create your lenses by hand. This isn't a big deal. For your test record above, to create a lens (or focus) by hand, you first need a getter function, which is trivial:

.a

And then a map function, which can apply a function to a given test :

\f test = { test | a = f test.a }

Now you can combine those two to make a focus:

a = Focus.create .a (\f test = { test | a = f test.a })

Do the same for b :

b = Focus.create .b (\f a = { a | b = f a.b })

And now you can combine these two foci with (a => b) and that lets you make the Focus.update call shown above. So there's a bit of boilerplate, but it's no great hardship, and you can do nested gets/sets/updates to your heart's content.

The bigger limitation is, you can't do prisms. So if there's a Maybe involved in your path, you're blocked. Back to doing the nested update the long-long-longhand way.

Why are there no prisms? Because they need higher kinded types, and Elm doesn't have those. (Yet?)

So the answer's yes & no. You can have something Lens-like, but don't expect the full power of Haskell lenses.

Update: Looks like I was wrong on my last point - Monacle provides Prisms. I didn't think it was possible. I stand corrected!