#lang scribble/doc

@require[(planet cce/scheme:4:1/planet)
         (for-syntax scheme/base)
         scheme/runtime-path
         scribble/manual
         scribble/basic
         scribble/eval]

@require[(for-label scheme/base
                    (this-package-in set)
                    (this-package-in seteq))]

@define-runtime-path[here (build-path 'same)]

@define[the-eval
        (let ([the-eval (make-base-eval)])
          (parameterize ([current-directory here])
            (the-eval `(require (file ,(path->string (build-path here "main.ss")))))
            the-eval))]

@title[#:tag "top"]{@bold{Set}: Purely Functional Sets}

by Dave Herman (@tt{dherman at ccs dot neu dot edu})

This library provides two implementations of functional sets
backed by hash tables: one comparing elements for equality using
@scheme[equal?], the other using @scheme[eq?].

The data structures of this library are immutable. They are
implemented on top of PLT Scheme's immutable hash tables, and
therefore should have @italic{O}(1) running time for extending and
@italic{O}(@italic{log} @italic{n}) running time for lookup.

This library was inspired by
@link["http://srfi.schemers.org/srfi-1/srfi-1.html"]{SRFI-1}
and @link["http://www.haskell.org/ghc/"]{GHC}'s
@link["http://www.haskell.org/ghc/docs/latest/html/libraries/containers/Data-Set.html"]{@tt{Data.Set}} library.

@table-of-contents[]

@section[#:tag "started"]{Getting started}

The easiest way to use this library is to install its main module,
which exports all bindings in the two individual modules:

@defmodule/this-package[]

@examples[#:eval the-eval
          (define heroes (list->seteq '(rocky bullwinkle)))
          (define villains (list->seteq '(boris natasha)))
          (for ([x (seteq-union heroes villains)])
            (printf "~a~n" x))]

@section[#:tag "set"]{Sets using @scheme[equal?]}

@defmodule/this-package[set]

@defproc[(set? [x any]) boolean?]{Determines whether @scheme[x] is a set.}

@defproc[(list->set [ls list?]) set?]{
Produces a set containing the elements in @scheme[ls].
If @scheme[ls] contains duplicates (as determined by @scheme[equal?]),
the resulting set contains only the rightmost of the duplicate elements.}

@defproc[(set->list [s set?]) list?]{
Produces a list containing the elements in @scheme[s].
No guarantees are made about the order of the elements in the list.}

@defthing[empty-set set?]{An empty set.}

@defproc[(set-empty? [s set?]) boolean?]{Determines whether @scheme[s] is empty.}

@deftogether[(
@defproc[(set-intersection [sets set?] ...+) set?]
@defproc[(set-intersections [sets (nelistof set?)]) set?]
)]{Produces the set intersection of @scheme[sets].}

@deftogether[(
@defproc[(set-difference [sets set?] ...+) set?]
@defproc[(set-differences [sets (nelistof set?)]) set?]
)]{Produces the left-associative set difference of @scheme[sets].}

@deftogether[(
@defproc[(set-union [sets set?] ...) set?]
@defproc[(set-unions [sets? (listof set?)]) set?]
)]{Produces the set union of @scheme[sets].}

@deftogether[(
@defproc[(set-xor [sets set?] ...+) set?]
@defproc[(set-xors [sets (nelistof set?)]) set?]
)]{
Produces the exclusive union of @scheme[sets].
This operation is associative and extends to the @italic{n}-ary case
by producing a set of elements that appear in an odd number of
@scheme[sets].}

@deftogether[(
@defproc[(set-partition [sets set?] ...+) (values set? set?)]
@defproc[(set-partitions [sets (nelistof set?)]) (values set? set?)]
)]{
Equivalent to
@schemeblock[(values (set-differences sets)
                     (set-intersection (car sets) (unions (cdr sets))))]
but implemented more efficiently.

Note that this is @bold{not necessarily the same thing} as
@schemeblock[(values (set-differences sets)
                     (set-intersections sets)) #, '(code:comment "not the same thing!")]}

@defproc[(set-adjoin [s set?] [elts any] ...) set?]{Produces a set containing the elements of @scheme[s] and @scheme[elts].}

@defproc[(set-add [x any] [s set?]) set?]{Produces a set containing @scheme[x] and the elements of @scheme[s].}

@defproc[(set-contains? [s set?] [x any]) boolean?]{Determines whether the set @scheme[s] contains the element @scheme[x].}

@defproc[(set-count [s set?]) exact-nonnegative-integer?]{Produces the number of elements in @scheme[s].}

@deftogether[(
@defform[(for/set (for-clause ...) body ...+)]
@defform[(for*/set (for-clause ...) body ...+)]
)]{
Like @scheme[for/list] and @scheme[for*/list], respectively,
but the result is a set. The expressions in the @scheme[body] forms
must produce a single value, which is included in the resulting set.}

@defproc[(in-set [s set?]) sequence?]{
Produces a sequence that iterates over the elements of @scheme[s].

Sets themselves have the @scheme[prop:sequence] property and can therefore
be used as sequences.}

@defproc[(set=? [s1 set?] [s2 set?]) boolean?]{
Determines whether @scheme[s1] and @scheme[s2] contain exactly the same elements,
using @scheme[equal?] to compare elements.}

@defproc[(subset? [s1 set?] [s2 set?]) boolean?]{
Determines whether all elements of @scheme[s1] are contained in @scheme[s2]
(i.e., whether @scheme[s1] is an improper subset of @scheme[s2]),
using @scheme[equal?] to compare elements.}

@section[#:tag "seteq"]{Sets using @scheme[eq?]}

@defmodule/this-package[seteq]

@defproc[(seteq? [x any]) boolean?]{Determines whether @scheme[x] is a set.}

@defproc[(list->seteq [ls list?]) seteq?]{
Produces a set containing the elements in @scheme[ls].
If @scheme[ls] contains duplicates (as determined by @scheme[eq?]),
the resulting set contains only the rightmost of the duplicate elements.}

@defproc[(seteq->list [s seteq?]) list?]{
Produces a list containing the elements in @scheme[s].
No guarantees are made about the order of the elements in the list.}

@defthing[empty-seteq seteq?]{An empty set.}

@defproc[(seteq-empty? [s seteq?]) boolean?]{Determines whether @scheme[s] is empty.}

@deftogether[(
@defproc[(seteq-intersection [sets seteq?] ...+) seteq?]
@defproc[(seteq-intersections [sets (nelistof seteq?)]) seteq?]
)]{Produces the set intersection of @scheme[sets].}

@deftogether[(
@defproc[(seteq-difference [sets seteq?] ...+) seteq?]
@defproc[(seteq-differences [sets (nelistof seteq?)]) seteq?]
)]{Produces the left-associative set difference of @scheme[sets].}

@deftogether[(
@defproc[(seteq-union [sets seteq?] ...) seteq?]
@defproc[(seteq-unions [sets? (listof seteq?)]) seteq?]
)]{Produces the set union of @scheme[sets].}

@deftogether[(
@defproc[(seteq-xor [sets seteq?] ...+) seteq?]
@defproc[(seteq-xors [sets (nelistof seteq?)]) seteq?]
)]{
Produces the exclusive union of @scheme[sets].
This operation is associative and extends to the @italic{n}-ary case
by producing a set of elements that appear in an odd number of
@scheme[sets].}

@deftogether[(
@defproc[(seteq-partition [sets seteq?] ...+) (values seteq? seteq?)]
@defproc[(seteq-partitions [sets (nelistof seteq?)]) (values seteq? seteq?)]
)]{
Equivalent to
@schemeblock[(values (seteq-differences sets)
                     (seteq-intersection (car sets) (unions (cdr sets))))]
but implemented more efficiently.

Note that this is @bold{not necessarily the same thing} as
@schemeblock[(values (seteq-differences sets)
                     (seteq-intersections sets)) #, '(code:comment "not the same thing!")]}

@defproc[(seteq-adjoin [s seteq?] [elts any] ...) seteq?]{Produces a set containing the elements of @scheme[s] and @scheme[elts].}

@defproc[(seteq-add [x any] [s seteq?]) seteq?]{Produces a set containing @scheme[x] and the elements of @scheme[s].}

@defproc[(seteq-contains? [s seteq?] [x any]) boolean?]{Determines whether the set @scheme[s] contains the element @scheme[x].}

@defproc[(seteq-count [s seteq?]) exact-nonnegative-integer?]{Produces the number of elements in @scheme[s].}

@deftogether[(
@defform[(for/seteq (for-clause ...) body ...+)]
@defform[(for*/seteq (for-clause ...) body ...+)]
)]{
Like @scheme[for/list] and @scheme[for*/list], respectively,
but the result is a set. The expressions in the @scheme[body] forms
must produce a single value, which is included in the resulting set.}

@defproc[(in-seteq [s seteq?]) sequence?]{
Produces a sequence that iterates over the elements of @scheme[s].

Sets themselves have the @scheme[prop:sequence] property and can therefore
be used as sequences.}

@defproc[(seteq=? [s1 seteq?] [s2 seteq?]) boolean?]{
Determines whether @scheme[s1] and @scheme[s2] contain exactly the same elements,
using @scheme[eq?] to compare elements.}

@defproc[(subseteq? [s1 seteq?] [s2 seteq?]) boolean?]{
Determines whether all elements of @scheme[s1] are contained in @scheme[s2]
(i.e., whether @scheme[s1] is an improper subset of @scheme[s2]),
using @scheme[eq?] to compare elements.}

