Given a Chez Scheme record with many numeric fields that are contantly being mutated by small increments and decrements, usually by one, is there a way to write a macro that can mutate a field value by passing it the field? The way I accomplish this now is something like the following REPL transcript:
Chez Scheme Version 9.5.4
Copyright 1984-2020 Cisco Systems, Inc.
> (define-record-type r (fields (mutable x) (mutable y)
;; and so on...
))
> (define my-r (make-r 3 5
;; and so on...
))
> (r-x-set! my-r (+ (r-x my-r) 1))
> my-r
#[#{r gak6l6ll8wuv7yd61kiomgudo-2} 4 5]
It would be nice to have a simple macro, say inc!, that could do the mutating increment/decrement operations on the fields in the record. I started with something like a Scheme version of Lisps incf and decf,
(define-syntax inc!
(syntax-rules ()
((_ x) (begin (set! x (+ x 1)) x))))
(inc! (r-x my-r)) ;; Syntax error
Which works for "normal" variables (and makes it easy to implement dec!), but it doesn't use the mechanism to set mutable record fields, r-x-set! in this case.
Is there an obvious way to write such a macro? One where you can just pass a reference to the record field without having to write something different for each field?
You can construct a
-set!mutator from the given accessor. This can be done by converting the symbol for the accessor to a string and appending"-set!"to it. Thenevalcan be used to get the actual mutator procedure. Here is a macro that increments a specified field by some amountn:This can be used to create an
inc!macro:But, it would be nice to be able to increment multiple fields at the same time; here are
inc!anddec!macros that do that:Sample interaction:
A Note on the Use of
evalThe
increment-n!macro constructs a symbol which has already been bound to a mutator procedure. That symbol could then be bound tomut!directly, but then when the expression(mut! rec (+ (acc rec) n))is evaluated an exception would be raised sincemut!now evaluates to a symbol, e.g.,r-x-set!. We wantmut!to evaluate to a procedure in a procedure call. By callingevalon the constructed symbol first we get the mutator procedure which is bound to that symbol, binding it tomut!instead of the symbol.Here is a REPL interaction that illustrates the problem, and will hopefully help to clarify: