6.3.90.900
1.3.1 Structures
Racket’s structure system is an extremely useful tool to help model your problem domain, but using
them in a functional style can be laborious. To make this easier, lens provides helper
macros to automatically generate lenses for structure fields, which can be composed just like any
other lenses to allow easy functional programming with nested structs.
To start using lenses with structs, use the struct/lens form when defining a structure
instead of struct:
This will define a struct called point, and it will also produce two lenses,
point-x-lens and point-y-lens. It’s also possible to define lenses for an
existing structure type using define-struct-lenses.
If you don’t want to use the auto-definition behavior of struct/lens or
define-struct-lenses, you can also use struct-lens to create one-off lenses for
particular fields.
One created, structure lenses work just like any other lenses: they can be used with functions like
lens-view, lens-set, and lens-transform, and they can be composed with
other lenses to produce new ones.
> (lens-view point-x-lens (point 4 10)) |
4 |
> (lens-set point-y-lens (point 4 10) 15) |
(point 4 15) |
|
(point 12 10) |
Composition of struct lenses can make it much easier to write purely functional state transformations,
such as the “world programs” of How to Design Programs. For example, given some state:
It’s possible to write updater functions that manipulate nested state without completely destructuring
and rebuilding the structure each time:
> (define (perform-monster-attack world monster) | (lens-transform (lens-compose player-stats-health-lens | world-player-stats-lens) | world | (λ (hp) (- hp (monster-attack monster))))) |
|
|
> (let ([w (world 0 (player-stats 15 6))] | [m (monster 2)]) | (perform-monster-attack w m)) |
|
(world 0 (player-stats 13 6)) |