Unstable Lenses
(require unstable/lens) | package: lens |
This library provides additional features for the lens library that are non-final and may change in future releases. Do not depend on this library being backwards-compatible.
1 lens-view/thrush, lens-set/thrush, and lens-transform/thrush
procedure
(lens-view/thrush target lens ...) → any/c
target : any/c lens : lens?
procedure
(lens-view~> target lens ...) → any/c
target : any/c lens : lens?
> (lens-view/thrush '(a b ((c d) e f) g) third-lens first-lens second-lens) 'd
> (lens-view~> '(a b ((c d) e f) g) third-lens first-lens second-lens) 'd
procedure
(lens-set/thrush target lens ... #:-> new-view) → any/c target : any/c lens : lens? new-view : any/c
procedure
(lens-set~> target lens ... #:-> new-view) → any/c
target : any/c lens : lens? new-view : any/c
> (lens-set/thrush '(a b ((c d) e f) g) third-lens first-lens second-lens #:-> "sea") '(a b ((c "sea") e f) g)
> (lens-set~> '(a b ((c d) e f) g) third-lens first-lens second-lens #:-> "sea") '(a b ((c "sea") e f) g)
procedure
(lens-transform/thrush target lens ... #:-> transformer) → any/c target : any/c lens : lens? transformer : (-> any/c any/c)
procedure
(lens-transform~> target lens ... #:-> transformer) → any/c target : any/c lens : lens? transformer : (-> any/c any/c)
> (lens-transform/thrush '(a b ((c d) e f) g) third-lens first-lens second-lens #:-> symbol->string) '(a b ((c "d") e f) g)
> (lens-transform~> '(a b ((c d) e f) g) third-lens first-lens second-lens #:-> symbol->string) '(a b ((c "d") e f) g)
2 Lenses for nested data
syntax
(define-nested-lenses [base-id base-lens-expr] clause ...)
clause =
[sub-id sub-lens-expr clause ...]
(define-nested-lenses [top-middle top-middle-lens] [x middle-x-lens] [y middle-y-lens])
Clauses can be nested within other clauses as well:
> (struct/lens game (player1 player2) #:transparent)
> (struct/lens player (position score) #:transparent)
> (struct/lens position (x y) #:transparent)
> (define-nested-lenses [game-player1 game-player1-lens] [score player-score-lens] [position player-position-lens [x position-x-lens] [y position-y-lens]])
> (define-nested-lenses [game-player2 game-player2-lens] [score player-score-lens] [position player-position-lens [x position-x-lens] [y position-y-lens]])
> (define the-game (game (player (position 1 2) 5) (player (position 3 4) 6)))
> (lens-view game-player1-score-lens the-game) 5
> (lens-view game-player1-position-lens the-game) (position 1 2)
> (lens-view game-player1-position-x-lens the-game) 1
> (lens-set game-player1-score-lens the-game 9005) (game (player (position 1 2) 9005) (player (position 3 4) 6))
> (lens-set game-player1-position-lens the-game (position 2 0)) (game (player (position 2 0) 5) (player (position 3 4) 6))
> (lens-set game-player1-position-x-lens the-game 3) (game (player (position 3 2) 5) (player (position 3 4) 6))
3 Lenses for nested dictionaries
procedure
(dict-ref-nested-lens k ...) → (lens/c functional-dict? any/c)
k : any/c
> (define a-x (dict-ref-nested-lens 'a 'x))
> (lens-view a-x '([a [x . 1] [y . 2]] '[b [z . 3]])) 1
> (lens-set a-x '([a [x . 1] [y . 2]] '[b [z . 3]]) 100) '((a (x . 100) (y . 2)) '(b (z . 3)))
4 Filtering hash-tables
procedure
(hash-filterer-lens/key keep?)
→ (lens/c immutable-hash? immutable?) keep? : (-> any/c boolean?)
> (lens-view (hash-filterer-lens/key symbol?) (hash 'a 1 "b" 2 'c 3)) '#hash((a . 1) (c . 3))
> (lens-set (hash-filterer-lens/key symbol?) (hash 'a 1 "b" 2 'c 3) (hash 'd 4 'e 5)) '#hash((e . 5) (d . 4) ("b" . 2))
procedure
(hash-filterer-lens/value keep?)
→ (lens/c immutable-hash? immutable?) keep? : (-> any/c boolean?)
> (lens-view (hash-filterer-lens/value number?) (hash 'a 1 'b "two" 'c 3)) '#hash((a . 1) (c . 3))
> (lens-set (hash-filterer-lens/value number?) (hash 'a 1 'b "two" 'c 3) (hash 'd 4)) '#hash((d . 4) (b . "two"))
procedure
(hash-filterer-lens keep?)
→ (lens/c immutable-hash? immutable?) keep? : (-> any/c any/c boolean?)
> (lens-view (hash-filterer-lens =) (hash 1 1.0 2 45 3 3)) '#hash((1 . 1.0) (3 . 3))
> (lens-set (hash-filterer-lens =) (hash 1 1.0 2 45 3 3) (hash 4 4.0 5.0 5)) '#hash((2 . 45) (4 . 4.0) (5.0 . 5))
5 Conditional Lenses
procedure
pred : (-> target/c any/c) lens1 : (lens/c target/c view/c) lens2 : (lens/c target/c view/c)
> (define if-lens (lens-if list? first-lens (vector-ref-lens 0)))
> (lens-view if-lens '(1 2 3)) 1
> (lens-view if-lens '#(1 2 3)) 1
> (lens-set if-lens '(1 2 3) 'a) '(a 2 3)
> (lens-set if-lens '#(1 2 3) 'a) '#(a 2 3)
syntax
(lens-cond [pred-expr lens-expr] ...)
> (define cond-lens (lens-cond [list? first-lens] [vector? (vector-ref-lens 0)] [string? (string-ref-lens 0)]))
> (lens-view cond-lens '(1 2 3)) 1
> (lens-view cond-lens '#(1 2 3)) 1
> (lens-view cond-lens "123") #\1
> (lens-set cond-lens '(1 2 3) 'a) '(a 2 3)
> (lens-set cond-lens '#(1 2 3) 'a) '#(a 2 3)
> (lens-set cond-lens "123" #\a) "a23"
> (lens-view cond-lens 'none-of-the-above) lens-cond: no matching clause for target
target: 'none-of-the-above
expected: '(or/c list? vector? string?)
syntax
(lens-match [pat lens-expr] ...)
> (define lens (lens-match [(list a) first-lens] [(list a b) second-lens]))
> (lens-view lens '(1)) 1
> (lens-view lens '(1 2)) 2
> (lens-set lens '(1) 'a) '(a)
> (lens-set lens '(1 2) 'a) '(1 a)
6 Isomorphisms
procedure
(make-isomorphism-lens f inv) → lens?
f : (a/c . -> . b/c) inv : (b/c . -> . a/c)
> (lens-view symbol->string-lens 'something) "something"
> (lens-transform symbol->string-lens 'something (λ (s) (string-append "make-" s))) 'make-something
procedure
(isomorphism-lens? v) → boolean?
v : any/c
procedure
(isomorphism-lens-inverse iso-lens) → isomorphism-lens?
iso-lens : isomorphism-lens?
procedure
(make-isomorphism-lenses f inv)
→
isomorphism-lens? isomorphism-lens? f : (a/c . -> . b/c) inv : (b/c . -> . a/c)
(define-values [string->symbol-lens symbol->string-lens] (make-isomorphism-lenses string->symbol symbol->string))
procedure
(isomorphism-compose lens ...) → isomorphism-lens?
lens : isomorphism-lens?
procedure
(isomorphism-thrush lens ...) → isomorphism-lens?
lens : isomorphism-lens?
value
value
value
value
value
value
value
value
7 Joining lenses with an association list
procedure
(lens-join/assoc key lens ... ...)
→ (lens/c target/c (listof (cons/c key/c value/c))) key : key/c lens : (lens/c target/c value/c)
> (define a-b-lens (lens-join/assoc 'a first-lens 'b third-lens))
> (lens-view a-b-lens '(1 2 3)) '((a . 1) (b . 3))
> (lens-set a-b-lens '(1 2 3) '((a . 100) (b . 200))) '(100 2 200)
8 Lazy lenses and recursive lenses
syntax
(lazy-lens lens-expr)
syntax
(rec-lens rec-id lens-expr)
> (define (tree-map-lens item-lens) (rec-lens the-tree-lens (lens-cond [list? (map-lens the-tree-lens)] [else item-lens])))
> (lens-view (tree-map-lens symbol->string-lens) '(a (b (() c)) (d))) '("a" ("b" (() "c")) ("d"))
> (lens-set (tree-map-lens symbol->string-lens) '(a (b (() c)) (d)) '("hay" ("bee" (() "sea")) ("deep"))) '(hay (bee (() sea)) (deep))
9 Lenses that map over lists and vectors
> (lens-view (map-lens first-lens) '((a b) (c d) (e f))) '(a c e)
> (lens-set (map-lens first-lens) '((a b) (c d) (e f)) '(1 2 3)) '((1 b) (2 d) (3 f))
> (lens-transform (map-lens first-lens) '((a b) (c d) (e f)) (λ (xs) (map symbol->string xs))) '(("a" b) ("c" d) ("e" f))
procedure
(vector-map-lens lens) → lens?
lens : lens?
> (lens-view (vector-map-lens first-lens) '#((a b) (c d) (e f))) '#(a c e)
> (lens-set (vector-map-lens first-lens) '#((a b) (c d) (e f)) '#(1 2 3)) '#((1 b) (2 d) (3 f))
> (lens-transform (vector-map-lens first-lens) '#((a b) (c d) (e f)) (λ (xs) (vector->immutable-vector (vector-map symbol->string xs)))) '#(("a" b) ("c" d) ("e" f))
10 Lenses based on match patterns
syntax
(match-lens id pattern replacement)
> (define car-lens (match-lens a (cons a b) (cons a b)))
> (define cdr-lens (match-lens b (cons a b) (cons a b)))
> (define third-lens (match-lens c (list a b c d ...) (list* a b c d)))
> (define vector-second-lens (match-lens b (vector a b c ...) (apply vector a b c)))
> (define v2-of-l3-lens (match-lens d (list a b (vector c d e ...) f ...) (list* a b (apply vector c d e) f)))
11 Filtering sets
procedure
(set-filterer-lens pred)
→ (lens/c functional-set? functional-set?) pred : (-> any/c any/c)
> (lens-view (set-filterer-lens number?) (set 1 'a 2 'b 'c 3 'd 'e)) (set 1 3 2)
> (lens-set (set-filterer-lens number?) (set 1 'a 2 'b 'c 3 'd 'e) (set 4 5 6 7)) (set 5 7 'e 4 'd 6 'a 'b 'c)
> (lens-view (set-filterer-lens number?) '(a 1 2 3)) '(1 2 3)
> (lens-set (set-filterer-lens number?) '(a 1 2 3) '(1 2 3)) '(3 2 1 a)
; this breaks the lens laws according to equal? > (equal? '(a 1 2 3) '(3 2 1 a)) #f
; but not according to set=? > (set=? '(a 1 2 3) '(3 2 1 a)) #t
12 Lenses for membership of a set
procedure
(set-member-lens v) → (lens/c functional-set? boolean?)
v : any/c
13 Splitting Strings
> (lens-view (string-split-lens ",") "a,b,c") '("a" "b" "c")
> (lens-set (string-split-lens ",") "a,b,c" '("1" "2" "3")) "1,2,3"
> (lens-view (string-split-lens ",") ",b,c") '("" "b" "c")
> (lens-set (string-split-lens ",") ",b,c" '("a" "b" "c")) "a,b,c"
> (lens-view (string-split-lens ",") "a,b,c,") '("a" "b" "c" "")
> (lens-set (string-split-lens ",") "a,b,c," '("a" "b" "c" "d")) "a,b,c,d"
14 Joining lenses with structs
syntax
(lens-join/struct struct-id field-lens ...)
field-lens = lens-expr | field-keyword lens-expr
> (struct foo (a b) #:transparent)
> (define lens (lens-join/struct foo first-lens third-lens))
> (lens-view lens '(1 2 3)) (foo 1 3)
> (lens-set lens '(1 2 3) (foo 'a 'b)) '(a 2 b)
> (struct foo (a b) #:transparent)
> (lens-view (lens-join/struct foo first-lens third-lens) '(1 2 3)) (foo 1 3)
> (lens-view (lens-join/struct foo #:a first-lens #:b third-lens) '(1 2 3)) (foo 1 3)
> (lens-view (lens-join/struct foo #:b third-lens #:a first-lens) '(1 2 3)) (foo 1 3)
> (lens-view (lens-join/struct foo first-lens #:b third-lens) '(1 2 3)) (foo 1 3)
15 Converting between structs and lists
syntax
(struct->list-lens struct-id)
syntax
(list->struct-lens struct-id)
> (struct foo (a b c) #:transparent)
> (lens-view (struct->list-lens foo) (foo 1 2 3)) '(1 2 3)
> (lens-set (struct->list-lens foo) (foo 1 2 3) '(4 5 6)) (foo 4 5 6)
> (lens-view (list->struct-lens foo) '(1 2 3)) (foo 1 2 3)
> (lens-set (list->struct-lens foo) '(1 2 3) (foo 4 5 6)) '(4 5 6)
For structs that inherit from other structs, it puts the inherited fields first, so that it matches the arguments to the constructor:
> (struct foo (a b c) #:transparent)
> (struct bar foo (d e))
> (lens-view (struct->list-lens bar) (bar 1 2 3 4 5)) '(1 2 3 4 5)
> (lens-set (struct->list-lens bar) (bar 1 2 3 4 5) '(6 7 8 9 10)) (bar 6 7 8 ...)
> (lens-view (list->struct-lens bar) '(1 2 3 4 5)) (bar 1 2 3 ...)
> (lens-set (list->struct-lens bar) '(1 2 3 4 4) (bar 6 7 8 9 10)) '(6 7 8 9 10)
16 Nested struct lenses
syntax
(struct-nested-lens [struct-id field-id] ...)
> (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 (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]))
> (lens-view game-player-health-lens the-game) 10
> (lens-set game-player-health-lens the-game 20) (game (player (posn 0 0) (combat-stats 20 1)) 'foo-level)
syntax
(struct-nested-lens* struct-id both-id ... field-id)
> (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 (game (player (posn 0 0) (combat-stats 10 1)) 'foo-level)
> (define game-player-x-lens (struct-nested-lens* game player posn x))
> (lens-view game-player-x-lens the-game) 0
> (lens-set game-player-x-lens the-game 5) (game (player (posn 5 0) (combat-stats 10 1)) 'foo-level)
17 Struct-lens provide forms
syntax
(struct-lenses-out struct-id)
syntax
(struct+lenses-out struct-id)
18 Sublist lenses
procedure
(sublist-lens i j) → lens?
i : exact-nonnegative-integer? j : exact-nonnegative-integer?
> (lens-view (sublist-lens 1 4) '(0 1 2 3 4 5)) '(1 2 3)
> (lens-set (sublist-lens 1 4) '(0 1 2 3 4 5) '(a b c)) '(0 a b c 4 5)
19 Substring Lenses
procedure
(substring-lens start end) → (lens/c string? string?)
start : exact-nonnegative-integer? end : exact-nonnegative-integer?
> (lens-view (substring-lens 1 4) "abcdefg") "bcd"
> (lens-set (substring-lens 1 4) "abcdefg" "FOO") "aFOOefg"
> (lens-set (substring-lens 1 4) "kitten" "this string is too long!") substring-lens: contract violation
expected: (string-length-=/c 3)
given: "this string is too long!"
in: an and/c case of
the 3rd argument of
a part of the or/c of
method lens-set
the result result of
(->i
((start exact-nonnegative-integer?)
(end
(start)
(and/c
exact-nonnegative-integer?
(>=/c start))))
(result
(start end)
(lens/c
(string-length->=/c end)
(string-length-=/c (- end start)))))
contract from:
<pkgs>/lens/lens/private/string/substring.rkt
blaming: top-level
(assuming the contract is correct)
at: <pkgs>/lens/lens/private/string/substring.rkt:7.3
20 Syntax Lenses
syntax
(syntax-lens target-id structure)
procedure
(syntax-keyword-seq-lens kw) → lens?
kw : keyword?
> (define foo-kw-seq-lens (syntax-keyword-seq-lens '#:foo))
> (lens-view foo-kw-seq-lens #'(a #:foo c d #:bar f)) #<syntax:/home/racket/build-pkgs/user/.racket/6.3.90.900/pkgs/lens/lens/private/syntax/syntax-keyword.rkt:33:7 (c d)>
> (lens-set foo-kw-seq-lens #'(a #:foo c d #:bar f) #'(1 2 3 4 5 6)) #<syntax:/home/racket/build-pkgs/user/.racket/6.3.90.900/pkgs/lens/lens/private/syntax/syntax-keyword.rkt:41:11 (a #:foo 1 2 3 4 5 6 #:bar f)>
> (define foo-kw-seq-lens (syntax-keyword-seq-lens '#:foo))
> (lens-view foo-kw-seq-lens #'(a b f g)) #<syntax:/home/racket/build-pkgs/user/.racket/6.3.90.900/pkgs/lens/lens/private/syntax/syntax-keyword.rkt:27:43 ()>
> (lens-view foo-kw-seq-lens #'(a #:foo #:bar f)) #<syntax:/home/racket/build-pkgs/user/.racket/6.3.90.900/pkgs/lens/lens/private/syntax/syntax-keyword.rkt:33:7 ()>
> (lens-set foo-kw-seq-lens #'(a #:foo #:bar f) #'(1 2 3 4 5 6)) #<syntax:/home/racket/build-pkgs/user/.racket/6.3.90.900/pkgs/lens/lens/private/syntax/syntax-keyword.rkt:41:11 (a #:foo 1 2 3 4 5 6 #:bar f)>
> (lens-set foo-kw-seq-lens #'(a b f g) #'(these are ignored)) #<syntax:/home/racket/build-pkgs/user/.racket/6.3.90.900/pkgs/lens/lens/private/syntax/syntax-keyword.rkt:41:11 (a b f g)>
21 More Viewing and Setting
procedure
(lens-set-all target new-view lens ...) → any/c
target : any/c new-view : any/c lens : lens?
> (lens-set-all '(1 2 3 4 5) 'a first-lens third-lens fourth-lens) '(a 2 a a 5)
22 Lenses that transform subpieces
(lens-transform zoom-lens target (λ (v) (lens-view transform-lens v)))
> (define first-zoom-second-lens (lens-zoom first-lens second-lens))
> (lens-view first-zoom-second-lens '((1 2 3) b c)) '(2 b c)
> (lens-set first-zoom-second-lens '((1 2 3) b c) '(2000 b FOO)) '((1 2000 3) b FOO)
procedure
(lens-zoom* zoom-lens transform-lens ... ...) → lens?
zoom-lens : lens? transform-lens : lens?
> (define first-zoom-second/third-zoom-first-lens (lens-zoom* first-lens second-lens third-lens first-lens))
> (lens-view first-zoom-second/third-zoom-first-lens '((1 2 3) foo (a b c))) '(2 foo a)
> (lens-set first-zoom-second/third-zoom-first-lens '((1 2 3) foo (a b c)) '(200 FOO asdf)) '((1 200 3) FOO (asdf b c))