Zulip Chat Archive

Stream: lean4

Topic: Lens-like notation


Jovan Gerbscheid (Dec 23 2023 at 01:48):

Would it be possible to add a notation for updating a field structure? I often find myself with code like this:

withReader (fun c => { c with fvars := fvar :: c.fvars })

And I would much prefer something like

withReader (fvars %~ (fvar :: ·))

I don't mind what the syntax exactly looks like, but something like this would make code a lot cleaner.
For example in Haskell, this notation is possible using lenses, so maybe some of those features could be reproduced in lean.
Here's my simple attempt:

syntax ident "%~" : term
syntax ident "%~" term : term
macro_rules
| `($n:ident %~ $f $x) => `({ $x with $n:ident := $f $x.$n })
| `($n:ident %~ $f) => `(fun x => { x with $n:ident := $f x.$n })
| `($n:ident %~) => `(fun f x => { x with $n:ident := f x.$n })

#eval fst %~ (· + 1) (1,3) -- (2,3)

Alex J. Best (Dec 23 2023 at 10:57):

There was some work on lenses / optics in #282, which takes the approach of deriving with and modify functions rather than adding notation

Jovan Gerbscheid (Dec 23 2023 at 12:44):

I suppose the advantage of a notation is that you can use it on all data types since you don't have to explicitly derive_optics

Jovan Gerbscheid (Feb 26 2025 at 21:08):

Here's a version of the notation that works a bit better:

syntax term "%." noWs ident term:max : term

macro_rules
| `($struct %.$field:ident $f) => `({ $struct with $field:ident := $f $struct.$field })

variable (x : Nat × Nat × Nat)

#check x %.fst fun x => x + 1
#check x %.snd.snd (· + 1) %.fst (· + 1)

Jovan Gerbscheid (Feb 26 2025 at 21:20):

And, in do notation with mutable variables:

syntax ident ":=." noWs ident term : doElem

macro_rules
| `(doElem| $var:ident :=.$field:ident $f) => `(doElem| $var:ident := $var %.$field $f)

def foo : Id Nat := do
  let mut a : Nat × Nat := (100,1)
  a :=.fst (· + 1)
  return a.fst

#eval foo -- 101

Anand Rao Tadipatri (Feb 26 2025 at 21:26):

And here's syntax for modifying a mutable element in do notation (the previous message is specifically about modifying structure field, this is for any mutable variable):

syntax ident ":>" term : doElem

macro_rules
| `(doElem| $var:ident :> $f) => `(doElem| $var:ident := $f $var)

Last updated: May 02 2025 at 03:31 UTC