add append*-lens (#272)
This commit is contained in:
parent
b24d06d4e8
commit
a1f1907606
133
lens/private/list/append.rkt
Normal file
133
lens/private/list/append.rkt
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
#lang racket/base
|
||||||
|
|
||||||
|
(provide append*-lens append*n-lens)
|
||||||
|
|
||||||
|
(require lens racket/match racket/list)
|
||||||
|
|
||||||
|
(module+ test
|
||||||
|
(require rackunit syntax/parse lens/private/test-util/test-lens))
|
||||||
|
|
||||||
|
;; restore-structure : (Listof (Listof A)) (Listof B) -> (Listof (Listof B))
|
||||||
|
;; Takes a list of lists and a list and un-flattens the flattened
|
||||||
|
;; argument according to the structure of the structure arguement.
|
||||||
|
;; The length of the flattened list must be the same as the length
|
||||||
|
;; of (append* structure).
|
||||||
|
(define (restore-structure structure flattened)
|
||||||
|
(match structure
|
||||||
|
[(list)
|
||||||
|
(unless (empty? flattened)
|
||||||
|
(error 'append*-lens "flattened list is too long to match the structure"))
|
||||||
|
structure]
|
||||||
|
[(cons s-lst s-rst)
|
||||||
|
(define-values [f-lst f-rst]
|
||||||
|
(split-at flattened (length s-lst)))
|
||||||
|
(cons f-lst (restore-structure s-rst f-rst))]))
|
||||||
|
|
||||||
|
;; append*-lens : (Lens (Listof (Listof Any)) (Listof Any))
|
||||||
|
;; where the only valid views are lists with the same length as the
|
||||||
|
;; result of applying append* to the target.
|
||||||
|
(define append*-lens
|
||||||
|
(make-lens
|
||||||
|
append*
|
||||||
|
restore-structure))
|
||||||
|
|
||||||
|
(define (append*n-lens n)
|
||||||
|
(apply lens-thrush (make-list n append*-lens)))
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
(module+ test
|
||||||
|
(test-case "append*-lens"
|
||||||
|
(check-equal? (lens-view append*-lens (list (list 1) (list 2 3) (list)))
|
||||||
|
(list 1 2 3))
|
||||||
|
(check-equal? (lens-set append*-lens
|
||||||
|
(list (list 1) (list 2 3) (list))
|
||||||
|
(list 'a 'b 'c))
|
||||||
|
(list (list 'a) (list 'b 'c) (list)))
|
||||||
|
|
||||||
|
(check-equal? (lens-transform append*-lens
|
||||||
|
(list (list 1) (list 2 3) (list))
|
||||||
|
(lambda (lst)
|
||||||
|
;; a length-preserving computation
|
||||||
|
(let loop ([acc (list)] [sum 0] [lst lst])
|
||||||
|
(match lst
|
||||||
|
[(list) (reverse acc)]
|
||||||
|
[(cons fst rst)
|
||||||
|
(loop (cons (+ sum fst) acc)
|
||||||
|
(+ sum fst)
|
||||||
|
rst)]))))
|
||||||
|
(list (list 1) (list 3 6) (list)))
|
||||||
|
|
||||||
|
(check-equal? (lens-transform append*-lens
|
||||||
|
(list (list #'(+ a)) (list #'(- a b) #'(* c d)) (list))
|
||||||
|
(lambda (lst)
|
||||||
|
;; a length-preserving computation
|
||||||
|
(syntax-parse
|
||||||
|
(expand #`(#%expression (λ (a b c d) (#%app list #,@lst))))
|
||||||
|
#:literals (#%plain-lambda #%plain-app list)
|
||||||
|
[(#%expression (#%plain-lambda (x ...) (#%plain-app list e ...)))
|
||||||
|
(syntax->datum #'[e ...])])))
|
||||||
|
(list (list '(#%app + a))
|
||||||
|
(list '(#%app - a b) '(#%app * c d))
|
||||||
|
(list)))
|
||||||
|
|
||||||
|
(test-lens-laws append*-lens
|
||||||
|
(list (list 1) (list 2 3) (list))
|
||||||
|
(list 'a 'b 'c)
|
||||||
|
(list "a" "b" "c"))
|
||||||
|
)
|
||||||
|
|
||||||
|
(test-case "append*n-lens"
|
||||||
|
(define append**-lens (append*n-lens 2))
|
||||||
|
(define append***-lens (append*n-lens 3))
|
||||||
|
|
||||||
|
(check-equal? (lens-view append**-lens
|
||||||
|
(list (list (list) (list 1))
|
||||||
|
(list (list 2 3))
|
||||||
|
(list)
|
||||||
|
(list (list 4) (list) (list 5 6))))
|
||||||
|
(list 1 2 3 4 5 6))
|
||||||
|
(check-equal? (lens-set append**-lens
|
||||||
|
(list (list (list) (list 1))
|
||||||
|
(list (list 2 3))
|
||||||
|
(list)
|
||||||
|
(list (list 4) (list) (list 5 6)))
|
||||||
|
(list 'a 'b 'c 'd 'e 'f))
|
||||||
|
(list (list (list) (list 'a))
|
||||||
|
(list (list 'b 'c))
|
||||||
|
(list)
|
||||||
|
(list (list 'd) (list) (list 'e 'f))))
|
||||||
|
|
||||||
|
(test-lens-laws append**-lens
|
||||||
|
(list (list (list) (list 1))
|
||||||
|
(list (list 2 3))
|
||||||
|
(list)
|
||||||
|
(list (list 4) (list) (list 5 6)))
|
||||||
|
(list 'a 'b 'c 'd 'e 'f)
|
||||||
|
(list "a" "b" "c" "d" "e" "f"))
|
||||||
|
|
||||||
|
(check-equal? (lens-view append***-lens
|
||||||
|
(list (list (list) (list (list 1)))
|
||||||
|
(list (list (list) (list 2 3)))
|
||||||
|
(list)
|
||||||
|
(list (list (list 4) (list)) (list) (list (list 5 6)))))
|
||||||
|
(list 1 2 3 4 5 6))
|
||||||
|
(check-equal? (lens-set append***-lens
|
||||||
|
(list (list (list) (list (list 1)))
|
||||||
|
(list (list (list) (list 2 3)))
|
||||||
|
(list)
|
||||||
|
(list (list (list 4) (list)) (list) (list (list 5 6))))
|
||||||
|
(list 'a 'b 'c 'd 'e 'f))
|
||||||
|
(list (list (list) (list (list 'a)))
|
||||||
|
(list (list (list) (list 'b 'c)))
|
||||||
|
(list)
|
||||||
|
(list (list (list 'd) (list)) (list) (list (list 'e 'f)))))
|
||||||
|
|
||||||
|
(test-lens-laws append***-lens
|
||||||
|
(list (list (list) (list (list 1)))
|
||||||
|
(list (list (list) (list 2 3)))
|
||||||
|
(list)
|
||||||
|
(list (list (list 4) (list)) (list) (list (list 5 6))))
|
||||||
|
(list 'a 'b 'c 'd 'e 'f)
|
||||||
|
(list "a" "b" "c" "d" "e" "f"))
|
||||||
|
))
|
21
lens/private/list/append.scrbl
Normal file
21
lens/private/list/append.scrbl
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#lang scribble/manual
|
||||||
|
|
||||||
|
@(require "../doc-util/main.rkt")
|
||||||
|
|
||||||
|
@title{Flattening and unflattening lists}
|
||||||
|
|
||||||
|
@defthing[append*-lens lens?]{
|
||||||
|
A lens that flattens a list one-level down when viewing, and restores
|
||||||
|
the original structure when setting.
|
||||||
|
@lens-unstable-examples[
|
||||||
|
(lens-view append*-lens '((a) (b c) () (d e f)))
|
||||||
|
(lens-set append*-lens '((a) (b c) () (d e f)) '(1 2 3 4 5 6))
|
||||||
|
]}
|
||||||
|
|
||||||
|
@defproc[(append*n-lens [n exact-nonnegative-integer?]) lens?]{
|
||||||
|
Creates a lens that flattens a list @racket[n] levels down when
|
||||||
|
viewing, and restores the original structure when setting.
|
||||||
|
@lens-unstable-examples[
|
||||||
|
(lens-view (append*n-lens 2) '(((a) ()) (() (b) (c)) () ((d e) () (f))))
|
||||||
|
(lens-set (append*n-lens 2) '(((a) ()) (() (b) (c)) () ((d e) () (f))) '(1 2 3 4 5 6))
|
||||||
|
]}
|
2
unstable/lens/append.rkt
Normal file
2
unstable/lens/append.rkt
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
#lang reprovide
|
||||||
|
lens/private/list/append
|
|
@ -1,4 +1,5 @@
|
||||||
#lang reprovide
|
#lang reprovide
|
||||||
|
"append.rkt"
|
||||||
"arrow.rkt"
|
"arrow.rkt"
|
||||||
"define-nested.rkt"
|
"define-nested.rkt"
|
||||||
"dict-nested.rkt"
|
"dict-nested.rkt"
|
||||||
|
|
|
@ -12,6 +12,7 @@ may change in future releases. Do not depend on
|
||||||
this library being backwards-compatible.
|
this library being backwards-compatible.
|
||||||
|
|
||||||
@(include-sections
|
@(include-sections
|
||||||
|
(lib "lens/private/list/append.scrbl")
|
||||||
"arrow.scrbl"
|
"arrow.scrbl"
|
||||||
"define-nested.scrbl"
|
"define-nested.scrbl"
|
||||||
"dict-nested.scrbl"
|
"dict-nested.scrbl"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user