Split shorthand into separate macro, adjust docs
This commit is contained in:
parent
5a10edb1f3
commit
4965d54fa3
|
@ -8,27 +8,42 @@
|
||||||
(module+ test
|
(module+ test
|
||||||
(require rackunit))
|
(require rackunit))
|
||||||
|
|
||||||
(provide struct-nested-lens)
|
(provide struct-nested-lens
|
||||||
|
struct-nested-lens*)
|
||||||
|
|
||||||
|
|
||||||
(define-syntax 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
|
(syntax-parser
|
||||||
[(_ struct-id:id field-id:id)
|
[(_ struct-id:id field-id:id)
|
||||||
#'(struct-lens struct-id field-id)]
|
#'(struct-lens struct-id field-id)]
|
||||||
[(_ struct-id:id [field-id:id field-struct-id:id] rest ...)
|
[(_ struct-id:id both0:id both:id ... field-id:id)
|
||||||
#'(lens-thrush (struct-lens struct-id field-id)
|
#'(lens-thrush (struct-lens struct-id both0)
|
||||||
(struct-nested-lens field-struct-id rest ...))]
|
(struct-nested-lens* both0 both ... field-id))]))
|
||||||
[(_ 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 ...)]))
|
|
||||||
|
|
||||||
(module+ test
|
(module+ test
|
||||||
(struct a (b b2) #:prefab)
|
(struct game (player level) #:transparent)
|
||||||
(struct b (b1 b2 b3) #:prefab)
|
(struct player (posn stats) #:transparent)
|
||||||
(define a-b-b1-lens (struct-nested-lens a b b1))
|
(struct posn (x y) #:transparent)
|
||||||
(define a-b2-b3-lens (struct-nested-lens a [b2 b] b3))
|
(struct combat-stats (health attack) #:transparent)
|
||||||
(check-equal? (lens-view a-b-b1-lens (a (b 1 2 3) 'foo)) 1)
|
(define the-game (game (player (posn 0 0) (combat-stats 10 1)) 'foo-level))
|
||||||
(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)
|
(define game-player-health-lens
|
||||||
(check-equal? (lens-set a-b2-b3-lens (a 'foo (b 1 2 3)) 10) (a 'foo (b 1 2 10))))
|
(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)
|
@(define-persistant-lenses-unstable-examples struct-nested-examples)
|
||||||
|
|
||||||
@defform[#:id struct-nested-lens
|
@defform[#:id struct-nested-lens
|
||||||
(struct-nested-lens struct-id intermediate ... field-id)
|
(struct-nested-lens [struct-id field-id] ...)]{
|
||||||
#:grammar ([intermediate (code:line [subfield-id subfield-struct-id]) both-id])]{
|
Constructs a lens that views nested structures. Each @racket[struct-id] and
|
||||||
Constructs a lens that views nested structures. The first @racket[struct-id] is the
|
@racket[field-id] pair is paired into a lens for viewing that field of that
|
||||||
outermost struct type, the last @racket[field-id] is the innermost target field. Each
|
struct, then the list of lenses are @racket[lens-thrush]ed together.
|
||||||
@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.
|
|
||||||
|
|
||||||
For example, given a complicated nested tree of state representing a game:
|
For example, given a complicated nested tree of state representing a game:
|
||||||
@struct-nested-examples[
|
@struct-nested-examples[
|
||||||
|
@ -29,22 +25,39 @@
|
||||||
]
|
]
|
||||||
|
|
||||||
We can create a lens for traversing the nested structures of the game state.
|
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
|
At each step, we provide the name of the struct we're examining and the name
|
||||||
as the struct that that field is a value of.
|
of the field we wish to traverse into.
|
||||||
@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.
|
|
||||||
@struct-nested-examples[
|
@struct-nested-examples[
|
||||||
(define game-player-health-lens
|
(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-view game-player-health-lens the-game)
|
||||||
(lens-set game-player-health-lens the-game 20)
|
(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