Suppose I have a struct with many fields:
(struct my-struct (f1 f2 f3 f4))
If I am to return a new struct with f2
updated, I have
I like Alexis' macro! It has more of the "lens" flavor you wanted.
I also want to point out struct-copy. Given:
#lang racket
(struct my-struct (f1 f2 f3 f4) #:transparent)
(define s (my-struct 1 2 3 4))
You can use struct-copy
to set a value:
(struct-copy my-struct s [f2 200])
;;=> (my-struct 1 200 3 4)
Or to update a value:
(struct-copy my-struct s [f2 (* 100 (my-struct-f2 s))])
;;=> (my-struct 1 200 3 4)
Update: Thinking about this more, here are a few more ideas.
You could also update using match
's struct*
pattern:
(match s
[(struct* my-struct ([f2 f2]))
(struct-copy my-struct s [f2 (* 100 f2)])])
Of course, that's very verbose. On the other hand the struct*
pattern makes it easy to define a macro using the simpler
define-syntax-rule
:
;; Given a structure type and an instance of it, a field-id, and a
;; function, return a new structure instance where the field is the
;; value of applying the function to the original value.
(define-syntax-rule (struct-update struct-type st field-id fn)
(match st
[(struct* struct-type ([field-id v]))
(struct-copy struct-type st [field-id (fn v)])]))
(struct-update my-struct s f2 (curry * 100))
;;=> (my-struct 1 200 3 4)
Of course, setting is the special case where you give update a
const
function:
(struct-update my-struct s f2 (const 42))
;;=> (my-struct 1 42 3 4)
Finally, this is like struct-update
, but returns an updater function, in the spirit of Alexis' macro:
(define-syntax-rule (struct-updater struct-type field-id)
(λ (st fn)
(struct-update struct-type st field-id fn)))
(define update-f2 (struct-updater my-struct f2))
(update-f2 s (curry * 100))
;;=> (my-struct 1 200 3 4)
I'm not saying that any of this is idiomatic or efficient. But it's possible. :)