On this page:
lens?
make-lens
2.2.1 Lens Operations
lens-get
lens-set
lens-modify
lens-compose
2.2.2 Library Lenses
identity-lens
car-lens
cdr-lens
caar-lens
cadr-lens
cdar-lens
cddr-lens
struct-lens
2.2.3 Generic Lens Interface
gen:  lens
8.15.0.2

2.2 Lenses🔗ℹ

 (require ocular-patdown/optics/lens)
  package: ocular-patdown

This module’s bindings are also provided by ocular-patdown/optics.

A lens is a type of optic that has a single focus. Lenses can be used to focus on a field of a struct, the car of a pair, etc.

Examples:
> (define pair (cons 1 2))
> (lens-get car-lens pair)

1

> (lens-set car-lens pair #t)

'(#t . 2)

> (struct posn [x y] #:transparent)
> (define posn1 (posn 1 2))
> (define posn-x-lens (struct-lens posn x))
> (lens-get posn-x-lens posn1)

1

> (lens-set posn-x-lens posn1 3)

(posn 3 2)

procedure

(lens? val)  boolean?

  val : any/c
A predicate which recognizes lenses. To be more precise, it recognizes implementers of gen:lens.

Examples:
> (lens? car-lens)

#t

> (lens? list-traversal)

#f

> (lens? identity-iso)

#t

procedure

(make-lens getter setter)  lens?

  getter : (-> any/c any/c)
  setter : (-> any/c any/c any/c)
Constructor for lenses. getter should extract the focus from the target. setter should take in the target and the new value for the focus and return a copy of the target with the updated focus.

Examples:
> (define my-car-lens (make-lens car (lambda (pair val) (cons val (cdr pair)))))
> (lens? my-car-lens)

#t

> (lens-get my-car-lens (cons 1 2))

1

> (lens-set my-car-lens (cons 1 2) #t)

'(#t . 2)

There are a few laws lenses should obey:
  • Getting the focus after setting the focus returns the new focus.

    (equal? (lens-get lens (lens-set lens target focus)) focus)

  • Setting the focus using the current focus leaves the target unchanged.

    (equal? (lens-set lens target (lens-get lens target)) target)

  • Setting the focus twice is the same as setting it once with the second value.

    (equal? (lens-set lens (lens-set lens target focus1) focus2) (lens-set lens target focus2))

These laws should be obeyed for some reasonable definition of equality. If these laws are not obeyed, you may experience unexpected behavior.

Lenses should also be pure. In other words, lens operations should not mutate the target or the focus, or have any other side effects. For setters, it is recommended to create an updated copy of the original target rather than mutating it.

2.2.1 Lens Operations🔗ℹ

procedure

(lens-get lens target)  any/c

  lens : lens?
  target : any/c
Gets the focus from target under lens.

Examples:
> (lens-get car-lens (cons 1 2))

1

> (lens-get posn-x-lens (posn 3 4))

3

procedure

(lens-set lens target focus)  any/c

  lens : lens?
  target : any/c
  focus : any/c
Returns an updated target with focus as the new focus under lens.

Examples:
> (lens-set car-lens (cons 1 2) #t)

'(#t . 2)

> (lens-set posn-x-lens (posn 3 4) 9)

(posn 9 4)

procedure

(lens-modify lens target proc)  any/c

  lens : lens?
  target : any/c
  proc : (-> any/c any/c)
Returns an updated target with proc applied to the focus under lens.

Examples:
> (lens-modify car-lens (cons 1 2) sub1)

'(0 . 2)

> (lens-modify posn-x-lens (posn 3 4) -)

(posn -3 4)

procedure

(lens-compose lens ...)  lens?

  lens : lens?
Compose lenses like optic-compose.

Examples:
> (struct tree [val children] #:transparent)
> (define tree-first-child-lens (lens-compose (struct-lens tree children) car-lens))
> (lens-set tree-first-child-lens
             (tree 1 (list (tree 2 '()) (tree 3 '())))
             (tree #t '()))

(tree 1 (list (tree #t '()) (tree 3 '())))

> (define second-lens (lens-compose cdr-lens car-lens))
> (lens-set second-lens (list 1 2) #t)

'(1 #t)

> (define first-of-second-lens (lens-compose second-lens car-lens))
> (lens-set first-of-second-lens (list 1 (list 2 3)) #t)

'(1 (#t 3))

2.2.2 Library Lenses🔗ℹ

A lens that focuses on the entire target. The identity of lens-compose.

value

car-lens : lens?

A lens that focuses on the car of a pair.

Examples:
> (lens-get car-lens (cons 1 2))

1

> (lens-set car-lens (cons 1 2) #t)

'(#t . 2)

value

cdr-lens : lens?

A lens that focuses on the cdr of a pair.

Examples:
> (lens-get cdr-lens (cons 1 2))

2

> (lens-set cdr-lens (cons 1 2) #t)

'(1 . #t)

value

caar-lens : lens?

A lens that focuses on the caar of a pair.

value

cadr-lens : lens?

value

cdar-lens : lens?

value

cddr-lens : lens?

syntax

(struct-lens struct-id field-id maybe-parent)

 
maybe-parent = 
  | #:parent parent-struct-id
A lens that focuses on a field of a struct. Supply #:parent if the field is a field of a supertype.

Examples:
> (struct posn [x y] #:transparent)
> (define posn-x-lens (struct-lens posn x))
> (lens-get posn-x-lens (posn 3 4))

3

> (lens-set posn-x-lens (posn 3 4) 9)

(posn 9 4)

> (struct posn3 posn [z] #:transparent)
> (define posn3-z-lens (struct-lens posn3 z))
> (define posn3-x-lens (struct-lens posn3 x #:parent posn))
> (lens-set posn3-z-lens (posn3 1 2 3) 9)

(posn3 1 2 9)

> (lens-set posn3-x-lens (posn3 1 2 3) 9)

(posn3 9 2 3)

> (lens-set posn-x-lens (posn3 1 2 3) 9)

(posn 9 2)

If the supertype is not supplied for fields of supertypes, an update will yield an instance of the supertype.

2.2.3 Generic Lens Interface🔗ℹ

syntax

gen:lens

A generic interface for lenses.

Example:
> (struct make-lens (getter setter)
    #:methods gen:lens
    [(define (lens-get lens target) ((make-lens-getter lens) target))
     (define (lens-set lens target focus)
       ((make-lens-setter lens) target focus))])