diff --git a/collects/racket/set.rkt b/collects/racket/set.rkt index 48b95e07e4..c1b5b6ba88 100644 --- a/collects/racket/set.rkt +++ b/collects/racket/set.rkt @@ -3,12 +3,14 @@ racket/serialize racket/pretty racket/contract/base - racket/contract/combinator) + racket/contract/combinator + (only-in "private/for.rkt" prop:stream)) (provide set seteq seteqv set? set-eq? set-eqv? set-equal? set-empty? set-count set-member? set-add set-remove + set-first set-rest set-union set-intersect set-subtract set-symmetric-difference subset? proper-subset? set-map set-for-each @@ -84,7 +86,10 @@ (=? (set-ht set1) (set-ht set2))) (lambda (set hc) (add1 (hc (set-ht set)))) (lambda (set hc) (add1 (hc (set-ht set))))) - #:property prop:sequence (lambda (v) (*in-set v))) + #:property prop:sequence (lambda (v) (*in-set v)) + #:property prop:stream (vector (lambda (s) (set-empty? s)) + (lambda (s) (set-first s)) + (lambda (s) (set-rest s)))) ;; Not currently exporting this because I'm not sure whether this is the right semantics ;; for it yet, but it follows most closely the semantics of the old set/c implementation @@ -265,6 +270,20 @@ (define (proper-subset? one two) (subset* 'proper-subset? one two #t)) +(define (set-first set) + (unless (set? set) (raise-argument-error 'set-first "set?" set)) + (define ht (set-ht set)) + (if (zero? (hash-count ht)) + (raise-arguments-error 'set-first "given set is empty") + (hash-iterate-key ht (hash-iterate-first ht)))) + +(define (set-rest set) + (unless (set? set) (raise-argument-error 'set-rest "set?" set)) + (define ht (set-ht set)) + (if (zero? (hash-count ht)) + (raise-arguments-error 'set-rest "given set is empty") + (make-set (hash-remove ht (hash-iterate-key ht (hash-iterate-first ht)))))) + (define (set-map set proc) (unless (set? set) (raise-argument-error 'set-map "set?" 0 set proc)) (unless (and (procedure? proc) diff --git a/collects/scribblings/reference/sequences.scrbl b/collects/scribblings/reference/sequences.scrbl index e432a24162..2aec6adc3e 100644 --- a/collects/scribblings/reference/sequences.scrbl +++ b/collects/scribblings/reference/sequences.scrbl @@ -635,7 +635,7 @@ in the sequence. @; ====================================================================== @section[#:tag "streams"]{Streams} -A @deftech{stream} is a kind of sequence that supports functional +A @deftech{stream} is a kind of @tech{sequence} that supports functional iteration via @racket[stream-first] and @racket[stream-rest]. The @racket[stream-cons] form constructs a lazy stream, but plain lists can be used as stream, and functions such as @racket[in-range] and diff --git a/collects/scribblings/reference/sets.scrbl b/collects/scribblings/reference/sets.scrbl index 44cc41d0c1..95bba86875 100644 --- a/collects/scribblings/reference/sets.scrbl +++ b/collects/scribblings/reference/sets.scrbl @@ -11,9 +11,10 @@ set, elements are equivalent via @racket[equal?], @racket[eqv?], or element-comparison procedure (@racket[equal?], @racket[eqv?], or @racket[eq?]) and have equivalent elements. -A set can be used as a single-valued sequence (see -@secref["sequences"]). The elements of the set serve as elements -of the sequence. See also @racket[in-set]. +A set can be used as a @tech{stream} (see @secref["streams"]) and thus +as a single-valued @tech{sequence} (see @secref["sequences"]). The +elements of the set serve as elements of the stream or sequence. See +also @racket[in-set]. Operations on sets that contain elements that are mutated are unpredictable in much the same way that @tech{hash table} operations are @@ -50,6 +51,17 @@ Returns @racket[#t] if @racket[v] is in @racket[st], @racket[#f] otherwise.} +@defproc[(set-first [st (and/c set? (not/c set-empty?))]) any/c]{ + +Produces an unspecified element of @racket[st]. Multiple uses of +@racket[set-first] on @racket[st] produce the same result.} + + +@defproc[(set-rest [st (and/c set? (not/c set-empty?))]) set?]{ + +Removes @racket[(set-first st)] from @racket[st].} + + @defproc[(set-add [st set?] [v any/c]) set?]{ @margin-note{Like operations on immutable hash tables, ``constant diff --git a/collects/tests/racket/set.rktl b/collects/tests/racket/set.rktl index bb61caa233..09f6496d4b 100644 --- a/collects/tests/racket/set.rktl +++ b/collects/tests/racket/set.rktl @@ -34,6 +34,10 @@ (test #t set-member? (set 1 2 3) 3) (test #f set-member? (set 1 2 3) 4) +(test #t stream? (set 1 2 3)) +(test (set-first (set 1 2 3)) set-first (set 1 2 3)) +(test (set-remove (set 1 2 3) (set-first (set 1 2 3))) set-rest (set 1 2 3)) + (let ([s (set 1 2 3)]) (test #t equal? s (set-add (set-add (set-add (set) 1) 2) 3)) (test #t equal? (seteq 1 2 3) (seteq 1 2 3)) diff --git a/doc/release-notes/racket/HISTORY.txt b/doc/release-notes/racket/HISTORY.txt index 1241cab678..8f9a1c44a0 100644 --- a/doc/release-notes/racket/HISTORY.txt +++ b/doc/release-notes/racket/HISTORY.txt @@ -1,6 +1,7 @@ Version 5.3.0.24 Added PLTCOMPILEDROOTS and --compiled/-R command-line flag Added `reroot-path' +racket/set: added set-first and set-rest, sets are streams Version 5.3.0.23 Changed make-log-receiver to accept a logger name as an