Split shorthand into separate macro, adjust docs
This commit is contained in:
parent
5a10edb1f3
commit
4965d54fa3
|
@ -8,27 +8,42 @@
|
|||
(module+ test
|
||||
(require rackunit))
|
||||
|
||||
(provide struct-nested-lens)
|
||||
(provide struct-nested-lens
|
||||
struct-nested-lens*)
|
||||
|
||||
|
||||
(define-syntax struct-nested-lens
|
||||
(syntax-parser
|
||||
[(_ [struct-id:id field-id:id] ...)
|
||||
#'(lens-thrush (struct-lens struct-id field-id) ...)]))
|
||||
|
||||
(define-syntax struct-nested-lens*
|
||||
(syntax-parser
|
||||
[(_ struct-id:id field-id:id)
|
||||
#'(struct-lens struct-id field-id)]
|
||||
[(_ struct-id:id [field-id:id field-struct-id:id] rest ...)
|
||||
#'(lens-thrush (struct-lens struct-id field-id)
|
||||
(struct-nested-lens field-struct-id rest ...))]
|
||||
[(_ struct-id:id field-and-field-struct-id:id rest ...)
|
||||
#'(struct-nested-lens struct-id
|
||||
[field-and-field-struct-id field-and-field-struct-id]
|
||||
rest ...)]))
|
||||
[(_ struct-id:id both0:id both:id ... field-id:id)
|
||||
#'(lens-thrush (struct-lens struct-id both0)
|
||||
(struct-nested-lens* both0 both ... field-id))]))
|
||||
|
||||
(module+ test
|
||||
(struct a (b b2) #:prefab)
|
||||
(struct b (b1 b2 b3) #:prefab)
|
||||
(define a-b-b1-lens (struct-nested-lens a b b1))
|
||||
(define a-b2-b3-lens (struct-nested-lens a [b2 b] b3))
|
||||
(check-equal? (lens-view a-b-b1-lens (a (b 1 2 3) 'foo)) 1)
|
||||
(check-equal? (lens-set a-b-b1-lens (a (b 1 2 3) 'foo) 10) (a (b 10 2 3) 'foo))
|
||||
(check-equal? (lens-view a-b2-b3-lens (a 'foo (b 1 2 3))) 3)
|
||||
(check-equal? (lens-set a-b2-b3-lens (a 'foo (b 1 2 3)) 10) (a 'foo (b 1 2 10))))
|
||||
(struct game (player level) #:transparent)
|
||||
(struct player (posn stats) #:transparent)
|
||||
(struct posn (x y) #:transparent)
|
||||
(struct combat-stats (health attack) #:transparent)
|
||||
(define the-game (game (player (posn 0 0) (combat-stats 10 1)) 'foo-level))
|
||||
|
||||
(define game-player-health-lens
|
||||
(struct-nested-lens [game player]
|
||||
[player stats]
|
||||
[combat-stats health]))
|
||||
(check-equal? (lens-view game-player-health-lens the-game) 10)
|
||||
(check-equal? (lens-set game-player-health-lens the-game 20)
|
||||
(game (player (posn 0 0) (combat-stats 20 1)) 'foo-level))
|
||||
|
||||
(define game-player-posn-x-lens
|
||||
(struct-nested-lens* game player posn x))
|
||||
(check-equal? (lens-view game-player-posn-x-lens the-game) 0)
|
||||
(check-equal? (lens-set game-player-posn-x-lens the-game 3)
|
||||
(game (player (posn 3 0) (combat-stats 10 1)) 'foo-level)))
|
||||
|
||||
|
|
@ -9,14 +9,10 @@
|
|||
@(define-persistant-lenses-unstable-examples struct-nested-examples)
|
||||
|
||||
@defform[#:id struct-nested-lens
|
||||
(struct-nested-lens struct-id intermediate ... field-id)
|
||||
#:grammar ([intermediate (code:line [subfield-id subfield-struct-id]) both-id])]{
|
||||
Constructs a lens that views nested structures. The first @racket[struct-id] is the
|
||||
outermost struct type, the last @racket[field-id] is the innermost target field. Each
|
||||
@racket[intermediate] specifies how to walk down one level of the nested structs, and
|
||||
is either a pair of a @racket[subfield-id] and that field's struct type in
|
||||
@racket[subfield-struct-id], or a single @racket[both-id] in the common case that the
|
||||
field name is the same as the struct name.
|
||||
(struct-nested-lens [struct-id field-id] ...)]{
|
||||
Constructs a lens that views nested structures. Each @racket[struct-id] and
|
||||
@racket[field-id] pair is paired into a lens for viewing that field of that
|
||||
struct, then the list of lenses are @racket[lens-thrush]ed together.
|
||||
|
||||
For example, given a complicated nested tree of state representing a game:
|
||||
@struct-nested-examples[
|
||||
|
@ -29,22 +25,39 @@
|
|||
]
|
||||
|
||||
We can create a lens for traversing the nested structures of the game state.
|
||||
This takes advantage of the fact that each struct's fields are the same name
|
||||
as the struct that that field is a value of.
|
||||
@struct-nested-examples[
|
||||
(define game-player-posn-x-lens
|
||||
(struct-nested-lens game player posn x))
|
||||
(lens-view game-player-posn-x-lens the-game)
|
||||
(lens-set game-player-posn-x-lens the-game 3)
|
||||
]
|
||||
|
||||
In the case of the player's combat stats, the field is @italic{not} the
|
||||
same name as the @racket[combat-stats] struct. Therefore, we use the
|
||||
more verbose @racket[[subfield-id subfield-struct-id]] form for that
|
||||
step of the nested struct traversal.
|
||||
At each step, we provide the name of the struct we're examining and the name
|
||||
of the field we wish to traverse into.
|
||||
@struct-nested-examples[
|
||||
(define game-player-health-lens
|
||||
(struct-nested-lens game player [stats combat-stats] health))
|
||||
(struct-nested-lens [game player]
|
||||
[player stats]
|
||||
[combat-stats health]))
|
||||
(lens-view game-player-health-lens the-game)
|
||||
(lens-set game-player-health-lens the-game 20)
|
||||
]}
|
||||
|
||||
@(define-persistant-lenses-unstable-examples struct-nested*-examples)
|
||||
|
||||
@defform[#:id struct-nested-lens*
|
||||
(struct-nested-lens* struct-id both-id ... field-id)]{
|
||||
Like @racket[struct-nested-lens], but for the case where each nested
|
||||
field is named the same as it's struct type. For example, given the
|
||||
game state defined in the examples for @racket[struct-nested-lens]:
|
||||
@struct-nested*-examples[
|
||||
(struct game (player level) #:transparent)
|
||||
(struct player (posn stats) #:transparent)
|
||||
(struct posn (x y) #:transparent)
|
||||
(struct combat-stats (health attack) #:transparent)
|
||||
(define the-game (game (player (posn 0 0) (combat-stats 10 1)) 'foo-level))
|
||||
the-game
|
||||
]
|
||||
|
||||
Because each field is named the same as it's struct type, we can
|
||||
create a lens for viewing the player's x coordinate more succinctly
|
||||
than with @racket[struct-nested-examples]:
|
||||
@struct-nested*-examples[
|
||||
(define game-player-x-lens
|
||||
(struct-nested-lens* game player posn x))
|
||||
(lens-view game-player-x-lens the-game)
|
||||
(lens-set game-player-x-lens the-game 5)
|
||||
]}
|
||||
|
|
Loading…
Reference in New Issue
Block a user