From 42f3325d88c1f3c1f5c70cad4e93a26bb9e81c6c Mon Sep 17 00:00:00 2001 From: AlexKnauth Date: Fri, 28 Aug 2015 00:33:58 -0400 Subject: [PATCH 1/7] add lens-join/assoc --- unstable/lens/join-assoc.rkt | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 unstable/lens/join-assoc.rkt diff --git a/unstable/lens/join-assoc.rkt b/unstable/lens/join-assoc.rkt new file mode 100644 index 0000000..7ae1cf3 --- /dev/null +++ b/unstable/lens/join-assoc.rkt @@ -0,0 +1,32 @@ +#lang sweet-exp racket/base + +provide lens-join/assoc + +require lens/private/base/main + lens/private/compound/join-list + lens/private/list/assoc + racket/match + unstable/sequence +module+ test + require rackunit lens/private/list/main + +(define (lens-join/assoc . ks/lenses) + (match-define (list (list keys lenses) ...) + (for/list ([k/lens (in-slice 2 ks/lenses)]) + k/lens)) + (define key-lenses (map assoc-lens keys)) + (define list-lens (apply lens-join/list lenses)) + (make-lens + (λ (tgt) + (for/list ([k (in-list keys)] [lens (in-list lenses)]) + (cons k (lens-view lens tgt)))) + (λ (tgt nvw) + (lens-set list-lens tgt (apply lens-view/list nvw key-lenses))))) + +module+ test + (define a-b-lens (lens-join/assoc 'a first-lens + 'b third-lens)) + (check-equal? (lens-view a-b-lens '(1 2 3)) + '((a . 1) (b . 3))) + (check-equal? (lens-set a-b-lens '(1 2 3) '((a . 100) (b . 200))) + '(100 2 200)) From 59a1b7473a0f7a174e898404736af8f24e2d69cf Mon Sep 17 00:00:00 2001 From: AlexKnauth Date: Fri, 28 Aug 2015 09:42:12 -0400 Subject: [PATCH 2/7] add alternating->assoc-list etc. --- lens/private/compound/join-hash.rkt | 22 +++------- lens/private/compound/join-list.rkt | 26 +++++------ lens/private/util/alternating-list.rkt | 61 ++++++++++++++++++++++++++ unstable/lens/isomorphism/data.rkt | 3 ++ unstable/lens/join-assoc.rkt | 9 ++-- 5 files changed, 85 insertions(+), 36 deletions(-) create mode 100644 lens/private/util/alternating-list.rkt diff --git a/lens/private/compound/join-hash.rkt b/lens/private/compound/join-hash.rkt index a393e69..c4d1050 100644 --- a/lens/private/compound/join-hash.rkt +++ b/lens/private/compound/join-hash.rkt @@ -5,6 +5,7 @@ unstable/sequence fancy-app "../base/main.rkt" + "../util/alternating-list.rkt" "../util/immutable.rkt" "../util/list-pair-contract.rkt" "join-list.rkt") @@ -18,27 +19,14 @@ [lens-join/hash (->* () #:rest (listof2 any/c lens?) (lens/c any/c immutable-hash?))])) -(define (value-list->hash keys vs) - (make-immutable-hash (map cons keys vs))) - -(define (split-slice n vs) - (define grouped - (for/list ([group (in-slice n vs)]) - group)) - (define (get-ith i) - (map (list-ref _ i) grouped)) - (build-list n get-ith)) - -(module+ test - (check-equal? (split-slice 3 '(a 1 FOO b 2 BAR c 3 BAZ)) - '((a b c) (1 2 3) (FOO BAR BAZ)))) - +(define (keys+values->hash keys vs) + (make-immutable-hash (keys+values->assoc-list keys vs))) (define (lens-join/hash . keys/lenses) - (match-define (list keys lenses) (split-slice 2 keys/lenses)) + (define-values [keys lenses] (alternating-list->keys+values keys/lenses)) (define list-lens (apply lens-join/list lenses)) (define (get target) - (value-list->hash keys (lens-view list-lens target))) + (keys+values->hash keys (lens-view list-lens target))) (define (set target new-view-hash) (lens-set list-lens target (map (hash-ref new-view-hash _) keys))) (make-lens get set)) diff --git a/lens/private/compound/join-list.rkt b/lens/private/compound/join-list.rkt index 08f9ebc..55c970a 100644 --- a/lens/private/compound/join-list.rkt +++ b/lens/private/compound/join-list.rkt @@ -1,26 +1,24 @@ -#lang racket/base +#lang sweet-exp racket/base -(require racket/list - racket/contract - "../base/main.rkt") +require racket/list + racket/contract + "../base/main.rkt" + "../util/alternating-list.rkt" -(module+ test - (require rackunit - "../list/list-ref-take-drop.rkt")) +module+ test + require rackunit + "../list/list-ref-take-drop.rkt" -(provide - (contract-out - [lens-join/list (->* () #:rest (listof lens?) (lens/c any/c list?))])) +provide + contract-out + lens-join/list (->* () #:rest (listof lens?) (lens/c any/c list?)) -(define (zip xs ys) - (append-map list xs ys)) - (define (lens-join/list . lenses) (define (get target) (apply lens-view/list target lenses)) (define (set target new-views) - (apply lens-set/list target (zip lenses new-views))) + (apply lens-set/list target (keys+values->alternating-list lenses new-views))) (make-lens get set)) diff --git a/lens/private/util/alternating-list.rkt b/lens/private/util/alternating-list.rkt new file mode 100644 index 0000000..b57d5b4 --- /dev/null +++ b/lens/private/util/alternating-list.rkt @@ -0,0 +1,61 @@ +#lang sweet-exp racket/base + +provide alternating->assoc-list + assoc->alternating-list + keys+values->assoc-list + assoc-list->keys+values + keys+values->alternating-list + alternating-list->keys+values + +require racket/list + racket/match + unstable/sequence +module+ test + require rackunit + +(define (alternating->assoc-list alternating-list) + (for/list ([lst (in-slice 2 alternating-list)]) + (match-define (list a b) lst) + (cons a b))) + +(define (assoc->alternating-list alist) + (append* + (for/list ([(k v) (in-pairs alist)]) + (list k v)))) + +(define (keys+values->assoc-list keys values) + (map cons keys values)) + +(define (assoc-list->keys+values alist) + (values (map car alist) + (map cdr alist))) + +(define (keys+values->alternating-list keys values) + (append-map list keys values)) + +(define (alternating-list->keys+values alternating-list) + (for/lists (ks vv) ([lst (in-slice 2 alternating-list)]) + (match-define (list k v) lst) + (values k v))) + +module+ test + (check-equal? (alternating->assoc-list '(a 1 b 2)) '((a . 1) (b . 2))) + (check-equal? (alternating->assoc-list '(b 2 a 1)) '((b . 2) (a . 1))) + (check-equal? (assoc->alternating-list '((a . 1) (b . 2))) '(a 1 b 2)) + (check-equal? (assoc->alternating-list '((b . 2) (a . 1))) '(b 2 a 1)) + (check-equal? (keys+values->assoc-list '(a b) '(1 2)) '((a . 1) (b . 2))) + (check-equal? (keys+values->assoc-list '(b a) '(2 1)) '((b . 2) (a . 1))) + (check-equal? (keys+values->alternating-list '(a b) '(1 2)) '(a 1 b 2)) + (check-equal? (keys+values->alternating-list '(b a) '(2 1)) '(b 2 a 1)) + (let-values ([(ks vs) (assoc-list->keys+values '((a . 1) (b . 2)))]) + (check-equal? ks '(a b)) + (check-equal? vs '(1 2))) + (let-values ([(ks vs) (assoc-list->keys+values '((b . 2) (a . 1)))]) + (check-equal? ks '(b a)) + (check-equal? vs '(2 1))) + (let-values ([(ks vs) (alternating-list->keys+values '(a 1 b 2))]) + (check-equal? ks '(a b)) + (check-equal? vs '(1 2))) + (let-values ([(ks vs) (alternating-list->keys+values '(b 2 a 1))]) + (check-equal? ks '(b a)) + (check-equal? vs '(2 1))) diff --git a/unstable/lens/isomorphism/data.rkt b/unstable/lens/isomorphism/data.rkt index e7ea405..1187443 100644 --- a/unstable/lens/isomorphism/data.rkt +++ b/unstable/lens/isomorphism/data.rkt @@ -10,6 +10,7 @@ provide string->symbol-lens string->list-lens require lens/private/base/main + lens/private/util/alternating-list "base.rkt" module+ test @@ -24,6 +25,8 @@ module+ test (make-isomorphism-lenses list->vector vector->list)) (define-values [list->string-lens string->list-lens] (make-isomorphism-lenses list->string string->list)) +(define-values [alternating->assoc-list-lens assoc->alternating-list-lens] + (make-isomorphism-lenses alternating->assoc-list assoc->alternating-list)) (module+ test diff --git a/unstable/lens/join-assoc.rkt b/unstable/lens/join-assoc.rkt index 7ae1cf3..c398a53 100644 --- a/unstable/lens/join-assoc.rkt +++ b/unstable/lens/join-assoc.rkt @@ -5,21 +5,20 @@ provide lens-join/assoc require lens/private/base/main lens/private/compound/join-list lens/private/list/assoc + lens/private/util/alternating-list racket/match unstable/sequence module+ test require rackunit lens/private/list/main (define (lens-join/assoc . ks/lenses) - (match-define (list (list keys lenses) ...) - (for/list ([k/lens (in-slice 2 ks/lenses)]) - k/lens)) + (define-values [keys lenses] + (alternating-list->keys+values ks/lenses)) (define key-lenses (map assoc-lens keys)) (define list-lens (apply lens-join/list lenses)) (make-lens (λ (tgt) - (for/list ([k (in-list keys)] [lens (in-list lenses)]) - (cons k (lens-view lens tgt)))) + (keys+values->assoc-list keys (lens-view list-lens tgt))) (λ (tgt nvw) (lens-set list-lens tgt (apply lens-view/list nvw key-lenses))))) From d13145e6eaced25e6f4e0ad61156eaf3fd2bc1e0 Mon Sep 17 00:00:00 2001 From: AlexKnauth Date: Sun, 30 Aug 2015 17:27:46 -0400 Subject: [PATCH 3/7] provide and document lens-join/assoc --- unstable/lens/join-assoc.scrbl | 18 ++++++++++++++++++ unstable/lens/main.rkt | 1 + unstable/lens/main.scrbl | 1 + 3 files changed, 20 insertions(+) create mode 100644 unstable/lens/join-assoc.scrbl diff --git a/unstable/lens/join-assoc.scrbl b/unstable/lens/join-assoc.scrbl new file mode 100644 index 0000000..3b69d1e --- /dev/null +++ b/unstable/lens/join-assoc.scrbl @@ -0,0 +1,18 @@ +#lang scribble/manual + +@(require lens/private/doc-util/main) + +@title{Joining lenses with an association list} + +@defmodule[unstable/lens/join-assoc] + +@defproc[(lens-join/assoc [key key/c] [lens (lens/c target/c value/c)] ... ...) + (lens/c target/c (listof (cons/c key/c value/c)))]{ +Like @racket[lens-join/hash], except joins the keys and values into an +association list instead of a hash-table. +@lens-unstable-examples[ + (define a-b-lens (lens-join/assoc 'a first-lens + 'b third-lens)) + (lens-view a-b-lens '(1 2 3)) + (lens-set a-b-lens '(1 2 3) '((a . 100) (b . 200))) +]} diff --git a/unstable/lens/main.rkt b/unstable/lens/main.rkt index faa51dd..4393467 100644 --- a/unstable/lens/main.rkt +++ b/unstable/lens/main.rkt @@ -3,6 +3,7 @@ "dict-nested.rkt" "if.rkt" "isomorphism.rkt" +"join-assoc.rkt" "mapper.rkt" "match.rkt" "set-filterer.rkt" diff --git a/unstable/lens/main.scrbl b/unstable/lens/main.scrbl index dd30ab7..10d51a5 100644 --- a/unstable/lens/main.scrbl +++ b/unstable/lens/main.scrbl @@ -16,6 +16,7 @@ this library being backwards-compatible. "dict-nested.scrbl" "if.scrbl" "isomorphism.scrbl" + "join-assoc.scrbl" "mapper.scrbl" "match.scrbl" "set-filterer.scrbl" From 730363fbfd0b681e45ffd6781688d01c2ee307ff Mon Sep 17 00:00:00 2001 From: AlexKnauth Date: Sun, 30 Aug 2015 17:35:57 -0400 Subject: [PATCH 4/7] Use lens/c contracts in docs for other lens-join forms --- lens/private/compound/join-hash.scrbl | 3 ++- lens/private/compound/join-list.scrbl | 2 +- lens/private/compound/join-string.scrbl | 2 +- lens/private/compound/join-vector.scrbl | 3 ++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lens/private/compound/join-hash.scrbl b/lens/private/compound/join-hash.scrbl index f11dcf7..5fe63ab 100644 --- a/lens/private/compound/join-hash.scrbl +++ b/lens/private/compound/join-hash.scrbl @@ -3,7 +3,8 @@ @(require "../doc-util/main.rkt") -@defproc[(lens-join/hash [key any/c] [lens lens?] ... ...) lens?]{ +@defproc[(lens-join/hash [key key/c] [lens (lens/c target/c value/c)] ... ...) + (lens/c target/c (hash/c key/c value/c #:immutable #t))]{ Constructs a lens that combines the view of each @racket[lens] into a hash of views with @racket[key]s as the hash keys. In the same manner as @racket[lens-join/list], diff --git a/lens/private/compound/join-list.scrbl b/lens/private/compound/join-list.scrbl index e9f9cd1..e835b1c 100644 --- a/lens/private/compound/join-list.scrbl +++ b/lens/private/compound/join-list.scrbl @@ -2,7 +2,7 @@ @(require "../doc-util/main.rkt") -@defproc[(lens-join/list [lens lens?] ...) lens?]{ +@defproc[(lens-join/list [lens (lens/c target/c item/c)] ...) (lens/c target/c (listof item/c))]{ Constructs a lens that combines the view of each @racket[lens] into a list of views. This lens can be used to view and set a list of values in a single diff --git a/lens/private/compound/join-string.scrbl b/lens/private/compound/join-string.scrbl index 8db5482..7d958fe 100644 --- a/lens/private/compound/join-string.scrbl +++ b/lens/private/compound/join-string.scrbl @@ -3,7 +3,7 @@ @(require "../doc-util/main.rkt") -@defproc[(lens-join/string [lens lens?] ...) lens?]{ +@defproc[(lens-join/string [lens (lens/c target/c char?)] ...) (lens/c target/c immutable-string?)]{ Like @racket[lens-join/list], except the view is a string, not a list. Each @racket[lens] argument must return a @racket[char?] as a view. @lens-examples[ diff --git a/lens/private/compound/join-vector.scrbl b/lens/private/compound/join-vector.scrbl index d8ea98f..66bda68 100644 --- a/lens/private/compound/join-vector.scrbl +++ b/lens/private/compound/join-vector.scrbl @@ -3,7 +3,8 @@ @(require "../doc-util/main.rkt") -@defproc[(lens-join/vector [lens lens?] ...) lens?]{ +@defproc[(lens-join/vector [lens (lens/c target/c item/c)] ...) + (lens/c target/c (vector-immutableof item/c))]{ Like @racket[lens-join/list], except the view is a vector, not a list. @lens-examples[ (define vector-first-third-fifth-lens From 1bcf4fb74e5bfe5c4be6ff171f4c4bb41c8e87db Mon Sep 17 00:00:00 2001 From: AlexKnauth Date: Sun, 30 Aug 2015 19:42:12 -0400 Subject: [PATCH 5/7] use rest-> contract for lens-join/list --- lens/private/compound/join-list.rkt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lens/private/compound/join-list.rkt b/lens/private/compound/join-list.rkt index 55c970a..14a0ba7 100644 --- a/lens/private/compound/join-list.rkt +++ b/lens/private/compound/join-list.rkt @@ -4,6 +4,7 @@ require racket/list racket/contract "../base/main.rkt" "../util/alternating-list.rkt" + "../util/rest-contract.rkt" module+ test require rackunit @@ -11,7 +12,7 @@ module+ test provide contract-out - lens-join/list (->* () #:rest (listof lens?) (lens/c any/c list?)) + lens-join/list (rest-> lens? (lens/c any/c list?)) (define (lens-join/list . lenses) From c6c15305b21459889be7cd9811343c2afb4d9170 Mon Sep 17 00:00:00 2001 From: AlexKnauth Date: Sun, 30 Aug 2015 19:45:33 -0400 Subject: [PATCH 6/7] add contract for lens-join/assoc --- unstable/lens/join-assoc.rkt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/unstable/lens/join-assoc.rkt b/unstable/lens/join-assoc.rkt index c398a53..32e76ae 100644 --- a/unstable/lens/join-assoc.rkt +++ b/unstable/lens/join-assoc.rkt @@ -1,11 +1,15 @@ #lang sweet-exp racket/base -provide lens-join/assoc +require racket/contract/base +provide + contract-out + lens-join/assoc (->* [] #:rest (listof2 any/c lens?) (lens/c any/c (listof pair?))) require lens/private/base/main lens/private/compound/join-list lens/private/list/assoc lens/private/util/alternating-list + lens/private/util/list-pair-contract racket/match unstable/sequence module+ test From 3babd97c4c018eb888ed25e832ea8b06f6c83091 Mon Sep 17 00:00:00 2001 From: AlexKnauth Date: Sun, 30 Aug 2015 19:47:45 -0400 Subject: [PATCH 7/7] Revert "Use lens/c contracts in docs for other lens-join forms" This reverts commit 730363fbfd0b681e45ffd6781688d01c2ee307ff. --- lens/private/compound/join-hash.scrbl | 3 +-- lens/private/compound/join-list.scrbl | 2 +- lens/private/compound/join-string.scrbl | 2 +- lens/private/compound/join-vector.scrbl | 3 +-- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/lens/private/compound/join-hash.scrbl b/lens/private/compound/join-hash.scrbl index 5fe63ab..f11dcf7 100644 --- a/lens/private/compound/join-hash.scrbl +++ b/lens/private/compound/join-hash.scrbl @@ -3,8 +3,7 @@ @(require "../doc-util/main.rkt") -@defproc[(lens-join/hash [key key/c] [lens (lens/c target/c value/c)] ... ...) - (lens/c target/c (hash/c key/c value/c #:immutable #t))]{ +@defproc[(lens-join/hash [key any/c] [lens lens?] ... ...) lens?]{ Constructs a lens that combines the view of each @racket[lens] into a hash of views with @racket[key]s as the hash keys. In the same manner as @racket[lens-join/list], diff --git a/lens/private/compound/join-list.scrbl b/lens/private/compound/join-list.scrbl index e835b1c..e9f9cd1 100644 --- a/lens/private/compound/join-list.scrbl +++ b/lens/private/compound/join-list.scrbl @@ -2,7 +2,7 @@ @(require "../doc-util/main.rkt") -@defproc[(lens-join/list [lens (lens/c target/c item/c)] ...) (lens/c target/c (listof item/c))]{ +@defproc[(lens-join/list [lens lens?] ...) lens?]{ Constructs a lens that combines the view of each @racket[lens] into a list of views. This lens can be used to view and set a list of values in a single diff --git a/lens/private/compound/join-string.scrbl b/lens/private/compound/join-string.scrbl index 7d958fe..8db5482 100644 --- a/lens/private/compound/join-string.scrbl +++ b/lens/private/compound/join-string.scrbl @@ -3,7 +3,7 @@ @(require "../doc-util/main.rkt") -@defproc[(lens-join/string [lens (lens/c target/c char?)] ...) (lens/c target/c immutable-string?)]{ +@defproc[(lens-join/string [lens lens?] ...) lens?]{ Like @racket[lens-join/list], except the view is a string, not a list. Each @racket[lens] argument must return a @racket[char?] as a view. @lens-examples[ diff --git a/lens/private/compound/join-vector.scrbl b/lens/private/compound/join-vector.scrbl index 66bda68..d8ea98f 100644 --- a/lens/private/compound/join-vector.scrbl +++ b/lens/private/compound/join-vector.scrbl @@ -3,8 +3,7 @@ @(require "../doc-util/main.rkt") -@defproc[(lens-join/vector [lens (lens/c target/c item/c)] ...) - (lens/c target/c (vector-immutableof item/c))]{ +@defproc[(lens-join/vector [lens lens?] ...) lens?]{ Like @racket[lens-join/list], except the view is a vector, not a list. @lens-examples[ (define vector-first-third-fifth-lens