Unstable Lenses
1 lens-view/  thrush, lens-set/  thrush, and lens-transform/  thrush
lens-view/  thrush
lens-view~>
lens-set/  thrush
lens-set~>
lens-transform/  thrush
lens-transform~>
2 Lenses for nested data
define-nested-lenses
3 Lenses for nested dictionaries
dict-ref-nested-lens
4 Filtering hash-tables
hash-filterer-lens/  key
hash-filterer-lens/  value
hash-filterer-lens
5 Conditional Lenses
lens-if
lens-cond
lens-match
6 Isomorphisms
make-isomorphism-lens
isomorphism-lens?
isomorphism-lens-inverse
make-isomorphism-lenses
isomorphism-compose
isomorphism-thrush
string->symbol-lens
symbol->string-lens
number->string-lens
string->number-lens
list->vector-lens
vector->list-lens
list->string-lens
string->list-lens
7 Joining lenses with an association list
lens-join/  assoc
8 Lazy lenses and recursive lenses
lazy-lens
rec-lens
9 Lenses that map over lists and vectors
map-lens
vector-map-lens
10 Lenses based on match patterns
match-lens
11 Filtering sets
set-filterer-lens
12 Lenses for membership of a set
set-member-lens
13 Splitting Strings
string-split-lens
14 Joining lenses with structs
lens-join/  struct
15 Converting between structs and lists
struct->list-lens
list->struct-lens
16 Nested struct lenses
struct-nested-lens
struct-nested-lens*
17 Struct-lens provide forms
struct-lenses-out
struct+  lenses-out
18 Sublist lenses
sublist-lens
19 Substring Lenses
substring-lens
20 Syntax Lenses
syntax-lens
syntax-keyword-seq-lens
21 More Viewing and Setting
lens-set-all
22 Lenses that transform subpieces
lens-zoom
lens-zoom*
6.3.90.900

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?
Like lens-view, except that it can take multiple lenses, which are combined into a nested lens. The argument order is switched, so that the target comes first and the lens arguments come after it. (lens-view/thrush target lens ...) produces the same value as (lens-view (lens-thrush lens ...) target), but can be more efficient. The function lens-view~> is provided as a shorter version.

Examples:
> (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
Like lens-set, except that it can take multiple lenses, which again are combined into a nested lens. (lens-set/thrush target lens ... #:-> new-view) is equivalent to (lens-set (lens-thrush lens ...) target new-view), and lens-set~> is the shorter version.

Examples:
> (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)
Like lens-transform, except that it can take multiple lenses, just like lens-set/thrush. (lens-transform/thrush target lens ... #:-> transformer) is equivalent to (lens-transform (lens-thrush lens ...) target transformer), and lens-transform~> is the shorter verison.

Examples:
> (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
  ...]
A shorthand for defining composed lenses for nested data structures.

For example, if there is a top struct containing a middle struct, which contains an x field and a y field, a form like:
(define-nested-lenses [top-middle top-middle-lens]
  [x middle-x-lens]
  [y middle-y-lens])
Will define top-middle-x-lens and top-middle-y-lens as (lens-thrush top-middle-lens middle-x-lens) and (lens-thrush top-middle-lens middle-y-lens).

Clauses can be nested within other clauses as well:

Examples:
> (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
Similar to hash-ref-nested-lens, but for dicts.

Examples:
> (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?)
Creates a lens that filters a hash-table to keys that pass the predicate keep?.

Examples:
> (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?)
Like hash-filterer-lens/value, but filters based on values that pass keep?, not keys.

Examples:
> (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?)
Creates a lens that filters a hash-table by the predicate keep?, which takes the key and the value as its two arguments.

Examples:
> (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

(lens-if pred lens1 lens2)  (lens/c target/c view/c)

  pred : (-> target/c any/c)
  lens1 : (lens/c target/c view/c)
  lens2 : (lens/c target/c view/c)
Creates a lens that uses lens1 when the target satisfies pred, and uses lens2 when the target doesn’t satisfy pred.

Examples:
> (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] ... [else else-lens-expr])

(lens-cond [pred-expr lens-expr] ...)
Like lens-if, but based on cond instead of if. It creates a lens that uses the first lens if the target matches the first predicate, the second lens if the target matches the second predicate, and so on. If the target matches none of the predicates, an error is raised.

Examples:
> (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] ...)

Like lens-if and lens-cond, but based on pattern matching the target against each pat with match. It creates a lens that uses the first lens if the target matches the first pat, the second lens if it matches the second pat, and so on.

Examples:
> (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)
Creates a lens for an isomorphism. The f argument should be a function with an inverse, and the inv argument should be its inverse. The f function converts targets to views, and the inv function converts views to targets.

So for instance a symbol->string-lens could be defined with:

Examples:
> (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
A predicate that returns true when v is a lens constructed with make-isomorphism-lens, isomorphism-lens-inverse, or make-isomorphism-lenses, and returns false otherwise. All isomorphism lenses are also lenses according to lens?.

procedure

(isomorphism-lens-inverse iso-lens)  isomorphism-lens?

  iso-lens : isomorphism-lens?
Returns the inverse of iso-lens.

procedure

(make-isomorphism-lenses f inv)

  
isomorphism-lens? isomorphism-lens?
  f : (a/c . -> . b/c)
  inv : (b/c . -> . a/c)
Returns two values. The first value is the result of (make-isomorphism-lens f inv), and the second value is the inverse of that lens.

The lenses symbol->string-lens and string->symbol-lens, for example, are defined like this:

procedure

(isomorphism-compose lens ...)  isomorphism-lens?

  lens : isomorphism-lens?
Like lens-compose, but works only on isomorphism lenses, and returns an isomorphism lens. It is also more efficient than lens-compose.

procedure

(isomorphism-thrush lens ...)  isomorphism-lens?

  lens : isomorphism-lens?
Like lens-thrush, but works only on isomorphism lenses, and returns an isomorphism lens. It is also more efficient than lens-thrush.

Isomorphim lenses for string->symbol, number->string, and so on.

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)
Like lens-join/hash, except joins the keys and values into an association list instead of a hash-table.

Examples:
> (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)

Creates a lazy lens that lazily evaluates lens-expr and uses it to view and set the target.

Examples:
> (define lazy-first-lens
    (lazy-lens (begin (displayln "evaluating") first-lens)))
> lazy-first-lens

#<lens>

> (lens-view lazy-first-lens '(1 2 3))

evaluating

1

> (lens-set lazy-first-lens '(1 2 3) 'a)

'(a 2 3)

syntax

(rec-lens rec-id lens-expr)

Creates a potentially recursive lens, where lens-expr can refer to rec-id as a lazy version of itself.

Examples:
> (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

procedure

(map-lens lens)  lens?

  lens : lens?
Creates a lens that maps lens over a target list.

Examples:
> (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?
Creates a lens that maps lens over a target vector with vector-map.

Examples:
> (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)

Creates a lens for viewing the id within the pattern.

The replacement expression should be an expression such that (match target [pattern replacement]) produces a value equivalent to target, and should use id as the view.

Examples:
> (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)
Creates a lens that filters a set by the predicate pred.

Examples:
> (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)

Lists are also sets, so set-filterer-lens works for lists too, but it does not preserve ordering. It follows the lens laws only if you compare using set=?, not equal?.

Examples:
> (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
Creates a lens for telling whether v is a member of the target set.

Examples:
> (define 2-lens (set-member-lens 2))
> (lens-view 2-lens (set 1 2 3))

#t

> (lens-view 2-lens (set 1 3))

#f

> (lens-set 2-lens (set 1 2 3) #t)

(set 1 3 2)

> (lens-set 2-lens (set 1 2 3) #f)

(set 1 3)

> (lens-set 2-lens (set 1 3) #t)

(set 1 3 2)

> (lens-set 2-lens (set 1 3) #f)

(set 1 3)

13 Splitting Strings

procedure

(string-split-lens sep)  lens?

  sep : (or/c string? char? regexp?)
Creates a lens that splits a string into multiple pieces like regexp-split or string-split.

Examples:
> (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"

Lenses created by string-split-lens do not trim strings first, so that when viewing a target that either starts or ends with something matching sep, the view will include empty strings as the first or last element, which is consistant with regexp-split or string-split with #:trim? #f. This is also more useful when using lens-set.

Examples:
> (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
Like lens-join/list, except that the views of the given lenses are put in an instance of the struct-id struct instead of in a list.

Examples:
> (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 fields in a lens-join/struct form can also be specified by keywords, in any order, and even with some fields specied by position and some by keywords:

Examples:
> (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)

Lenses that convert between structs and lists.

Examples:
> (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:

Examples:
> (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] ...)

Constructs a lens that views nested structures. Each struct-id and field-id pair is paired into a lens for viewing that field of that struct, then the list of lenses are lens-thrushed together.

For example, given a complicated nested tree of state representing a game:

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

(game (player (posn 0 0) (combat-stats 10 1)) 'foo-level)

We can create a lens for traversing the nested structures of the game state. At each step, we provide the name of the struct we’re examining and the name of the field we wish to traverse into.

Examples:
> (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)

Like struct-nested-lens, but for the case where each nested field is named the same as its struct type. For example, given the game state defined in the examples for struct-nested-lens:

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

(game (player (posn 0 0) (combat-stats 10 1)) 'foo-level)

Because each field is named the same as its struct type, we can create a lens for viewing the player’s x coordinate more succinctly than with struct-nested-examples:

Examples:
> (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)

A provide sub-form that provides the lenses defined by define-struct-lenses or struct/lens.

syntax

(struct+lenses-out struct-id)

A provide sub-form short for using both struct-out and struct-lenses-out.

18 Sublist lenses

Examples:
> (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?
Creates a lens that views a substring from start to end of a given string. start is inclusive and end is exclusive, in the same way as for substring.

Examples:
> (lens-view (substring-lens 1 4) "abcdefg")

"bcd"

> (lens-set (substring-lens 1 4) "abcdefg" "FOO")

"aFOOefg"

When setting a new view, the replacement string has to be the same length as the span of the substring lens to uphold the lens laws.

Example:
> (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)

Constructs a lens that parses a syntax object and returns a piece of that syntax object as determined by where target-id appears in structure.

Examples:
> (define first-of-second-stx-lens
    (syntax-lens A
      (_ (A _ ...) _ ...)))
> (lens-view first-of-second-stx-lens
             #'(foo (1 2 3) bar baz (blah blah)))

#<syntax:9:0 1>

> (lens-set first-of-second-stx-lens
            #'(define (f a) a)
            #'g)

#<syntax (define (g a) a)>

procedure

(syntax-keyword-seq-lens kw)  lens?

  kw : keyword?
Constructs a lens that examines a non-flat syntax object and views a syntax object containing all the terms in the target syntax that appear after kw but before any other keyword.

Examples:
> (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)>

If the target syntax object has no occurence of kw, or if the occurence of kw is at the end of the syntax object or immediately followed by another keyword, then viewing produces the empty list syntax object #'(). In the case where kw is not present, setting is a no-op.

Examples:
> (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?
Sets the view of target through each lens to new--view

Example:
> (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

procedure

(lens-zoom zoom-lens transform-lens)  lens?

  zoom-lens : lens?
  transform-lens : lens?
Creates a lens that transforms the subpiece of the target that zoom-lens views with transform-lens.

(lens-view (lens-zoom zoom-lens transform-lens) target)

is equivalent to:

(lens-transform zoom-lens target (λ (v) (lens-view transform-lens v)))

Examples:
> (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?
A multi-arg version of lens-zoom, analogous to lens-transform/list. It is equivalent to (lens-thrush (lens-zoom zoom-lens transform-lens) ...).

Examples:
> (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))