Adding structure fields
So, I have Racket struct
, stats:
(struct stats (str con dex int wis cha))
And I have a function add-stats
:
(define (modify-stats mods base)
(stats (+ (stats-str mods)
(stats-str base))
(+ (stats-con mods)
(stats-con base))
(+ (stats-dex mods)
(stats-dex base))
(+ (stats-int mods)
(stats-int base))
(+ (stats-wis mods)
(stats-wis base))
(+ (stats-cha mods)
(stats-cha base))))
Obviously this is really messy and there is a lot of unwanted repetition. I managed to shorten it to a more readable version:
(define (modify-stats mods base)
(define (add-stat statid)
(+ (statid mods)
(statid base)))
(stats (add-stat stats-str)
(add-stat stats-con)
(add-stat stats-dex)
(add-stat stats-int)
(add-stat stats-wis)
(add-stat stats-cha)))
But there are still many repetitions of "stat (s)". Is there a cleaner way I can perform operations on fields of two structures of the same type?
UPDATE: I managed to do it a little better:
(define (stat a-stat stats)
(match a-stat
["str" (stats-str stats)]
["con" (stats-con stats)]
["dex" (stats-dex stats)]
["int" (stats-int stats)]
["wis" (stats-wis stats)]
["cha" (stats-cha stats)]
[_ (error "Not a stat!")]))
(define (modify-stats mods base)
(define (add-stat string)
(+ (stat string mods)
(stat string base)))
(stats (add-stat "str")
(add-stat "con")
(add-stat "dex")
(add-stat "int")
(add-stat "wis")
(add-stat "cha")))
+3
source to share
1 answer
Without a second thought, here's one way to do it:
(define (modify-stats mods base)
(define (get-fields obj)
(map (lambda (getter) (getter obj))
(list stats-str stats-con stats-dex stats-int stats-wis stats-cha)))
(apply stats (map + (get-fields mods) (get-fields base))))
Loath, since I suggest using macros to improve performance, this macro generates exactly the same code as the OP's first version:
(require (for-syntax racket/syntax))
(define modify-stats
(let-syntax
((bump (lambda (stx)
(define (bump-attr attr)
(with-syntax ((getter (format-id attr "stats-~a" attr #:source attr)))
#'(+ (getter mods) (getter base))))
(syntax-case stx ()
((_ attr ...)
(with-syntax (((bumped ...) (map bump-attr (syntax->list #'(attr ...)))))
#'(lambda (mods base)
(stats bumped ...))))))))
(bump str con dex int wis cha)))
+4
source to share