|(require struct-update)||package: struct-update-lib|
Racket encourages programming in a functional style, which in turn encourages immutability. When manipulating immutable data structures, it is important to be able to functionally update those data structures—that is, copy them with certain values replaced. Racket provides functions like hash-set and hash-update for functionally updating data structures, but while the struct form produces immutable structures by default, it does not define any similar updaters automatically.
This library provides a define-struct-updaters form to accomplish that task. For a built-in solution to the same problem, see struct-copy. For a more powerful solution (especially useful for updating nested data structures), consider the lens library.
Two functions are generated for each field. Their names are generated by appending -set and -update onto each of the accessor functions, and they are unhygienically bound using the lexical context of struct-id. Each setter function is protected by the contract (-> struct-id? any/c struct-id?), and each updater functions is protected by the contract (-> struct-id? (-> any/c any/c) struct-id?).
> (struct point (x y) #:transparent) > (define-struct-updaters point) > (point-x-set (point 1 2) 10)
(point 10 2)
> (point-y-update (point 1 2) add1)
(point 1 3)
If struct-id is a substruct of a parent struct, super-id, then it generates setters and updaters for the super fields as well. These are generated with the names struct-id-super-id-field-id-set and struct-id-super-id-field-id-update. These will functionally update the fields of the parent struct, but they will produce instances of struct-id instead of super-id.
> (struct object (mass position) #:transparent) > (struct movable object (velocity) #:transparent) > (define-struct-updaters object) > (define-struct-updaters movable) > (object-mass-set (object 5 (list 1 2)) 10)
(object 10 '(1 2))
> (object-mass-set (movable 5 (list 1 2) (list 0 0)) 10)
(object 10 '(1 2))
> (movable-velocity-set (movable 5 (list 1 2) (list 0 0)) (list -3 -4))
(movable 5 '(1 2) '(-3 -4))
> (movable-object-mass-set (movable 5 (list 1 2) (list 0 0)) 10)
(movable 10 '(1 2) '(0 0))