From c4684c12e6ac087f92d28f2a547be0904146c6dd Mon Sep 17 00:00:00 2001 From: Jay McCarthy Date: Tue, 18 Nov 2014 08:38:42 -0500 Subject: [PATCH] Fixing exports and actually adding docs --- .../data-doc/data/scribblings/enumerate.scrbl | 666 ++++++++++++++++++ pkgs/data-pkgs/data-lib/data/enumerate.rkt | 3 + 2 files changed, 669 insertions(+) create mode 100644 pkgs/data-pkgs/data-doc/data/scribblings/enumerate.scrbl diff --git a/pkgs/data-pkgs/data-doc/data/scribblings/enumerate.scrbl b/pkgs/data-pkgs/data-doc/data/scribblings/enumerate.scrbl new file mode 100644 index 0000000000..6e1ad3b62c --- /dev/null +++ b/pkgs/data-pkgs/data-doc/data/scribblings/enumerate.scrbl @@ -0,0 +1,666 @@ +#lang scribble/manual +@(require scribble/eval + (for-label data/enumerate + racket/contract + racket/base)) + +@title{Enumerations} + +@(define the-eval (make-base-eval)) +@(the-eval '(require data/enumerate racket/string)) + +@defmodule[data/enumerate] + +@author[@author+email["Max S. New" "maxsnew@gmail.com"]] + +This library defines @deftech{enumerations}. Enumerations are +bijections between the natural numbers (or a prefix thereof) and a +data-type. Most of the bijections defined in this library guarantee +that the enumeration is efficient, meaning that the decoding a number +is linear in the bits of the number. + +@; XXX explain fairness +@; XXX add citations + +@defproc[(nat? [x any/c]) boolean?]{ + +Identifies a value as a natural number.} + +@defproc[(extended-nat? [x any/c]) boolean?]{ + +Identifies a value as a natural number or positive infinity.} + +@defproc[(enum [size extended-nat?] + [from (-> nat? any/c)] + [to (-> any/c nat?)]) + enum?]{ + +Constructs an @tech{enumeration} of size @racket[size] where +@racket[from] is the decoding function and @racket[to] is the encoding +function. } + +@defproc[(enum? [x any/c]) boolean?]{ + +Identifies a value as an @tech{enumeration}.} + +@defproc[(size [e enum?]) extended-nat?]{ + +Returns the size of an @tech{enumeration}.} + +@defproc[(decode [e enum?] [n nat?]) any/c]{ + +Uses @racket[e] to decode @racket[n].} + +@defproc[(encode [e enum?] [x any/c]) nat?]{ + +Uses @racket[e] to encode @racket[x].} + +@defthing[nat/e enum?]{ + +An @tech{enumeration} of the natural numbers. + +@examples[#:eval the-eval +(decode nat/e 5) +(encode nat/e 5) +]} + +@defproc[(map/e [f (-> a ... b)] + [inv-f (-> b (values a ...))] + [e enum?] ...+) enum?]{ + +Uses @racket[f] and @racket[inv-f] around the encoding and decoding +functions of @racket[e]. + +@examples[#:eval the-eval +(define map-1/e + (map/e number->string string->number nat/e)) +(decode map-1/e 5) +(encode map-1/e "5") +(define map-2/e + (map/e (λ (x y) + (string-join + (list (number->string x) + (number->string y)))) + (λ (x) + (apply values (map string->number (string-split x)))) + nat/e nat/e)) +(decode map-2/e 5) +(encode map-2/e "1 2") +]} + +@defproc[(filter/e [e enum?] [p (-> any/c boolean?)]) enum?]{ + +Returns an @tech{enumeration} identical to @racket[e] except that only +elements where @racket[p] returns true are included. The encoding +function and the size are wrong in the result and this is inefficient, +so only use it for very small enumerations. + +@examples[#:eval the-eval +(define filter-1/e + (filter/e nat/e even?)) +(decode filter-1/e 5) +(encode filter-1/e 8) +]} + +@defproc[(except/e [e enum?] [x any/c] ...) enum?]{ + +Returns an @tech{enumeration} identical to @racket[e] except that all +@racket[x] are not included in the decoding and cannot be encoded. + +@examples[#:eval the-eval +(define except-1/e + (except/e nat/e 3)) +(decode except-1/e 5) +(encode except-1/e 8) +]} + +@defproc[(to-stream [e enum?]) stream?]{ + +Returns a stream of the values in @racket[e]. + +@examples[#:eval the-eval +(to-stream map-2/e) +]} + +@defproc[(approximate [e enum?] [n nat?]) list?]{ + +Returns a list of the first @racket[n] values in @racket[e]. + +@examples[#:eval the-eval +(approximate map-2/e 5) +]} + +@defproc[(to-list [e enum?]) list?]{ + +Returns a list of the @racket[n] values in @racket[e]. This will +diverge if @racket[e] is infinite. + +@examples[#:eval the-eval +(to-list (take/e map-2/e 5)) +]} + +@defproc[(take/e [e enum?] [n nat?]) enum?]{ + +Identical to @racket[e] but only includes the first @racket[n] values. + +@examples[#:eval the-eval +(decode (take/e map-2/e 5) 3) +(encode (take/e map-2/e 5) "1 1") +]} + +@defproc[(slice/e [e enum?] [lo nat?] [hi nat?]) enum?]{ + +Identical to @racket[e] but only includes the values between +@racket[lo] and @racket[hi]. + +@examples[#:eval the-eval +(to-list (slice/e map-2/e 5 10)) +]} + +@defproc[(below/e [max nat?]) enum?]{ + +An @tech{enumeration} of the first @racket[max] naturals. + +@examples[#:eval the-eval +(to-list (below/e 10)) +]} + +@defthing[empty/e enum?]{ + +An empty @tech{enumeration}. + +@examples[#:eval the-eval +(to-list empty/e) +]} + +@defproc[(const/e [x any/c]) enum?]{ + +An @tech{enumeration} of exactly @racket[x]. + +@examples[#:eval the-eval +(to-list (const/e 42)) +]} + +@defproc[(from-list/e [xs list?]) enum?]{ + +An @tech{enumeration} of each @racket[eq?] value in +@racket[xs]. @racket[xs] should not contain duplicates, but +@racket[from-list/e] doesn't check. + +@examples[#:eval the-eval +(to-list (from-list/e '("Brian" "Jenny" "Ki" "Ted"))) +]} + +@defproc[(fin/e [x any/c] ...) enum?]{ + +An @tech{enumeration} of each @racket[x]. If a value is duplicated in +the input, it is only in the enumeration once. + +@examples[#:eval the-eval +(to-list (fin/e "Brian" "Jenny" "Ki" "Ted")) +]} + +@defthing[int/e enum?]{ + +An @tech{enumeration} of the integers. + +@examples[#:eval the-eval +(approximate int/e 10) +]} + +@defproc[(disj-sum/e [e-p (cons/c enum? (-> any/c boolean?))] ...) enum?]{ + +An @tech{enumeration} of the disjoint sum of the enumerations given in +@racket[e-p]. Each @racket[e-p] is a pair of an enumeration and a +predicate identifying elements of it. Only one or zero predicates +should return true on any value. + +@examples[#:eval the-eval +(approximate (disj-sum/e (cons nat/e nat?) (cons map-1/e string?)) 10) +]} + +@defproc[(disj-append/e [e-p (cons/c enum? (-> any/c boolean?))] ...+) enum?]{ + +An @tech{enumeration} of the disjoint sum of the enumerations given in +@racket[e-p] that fully enumerates each enumeration before enumerating +the next. @racket[e-p] are formatted as in @racket[disj-sum/e]. All +but the last enumeration should be finite. + +@examples[#:eval the-eval +(approximate (disj-append/e (cons (take/e nat/e 4) nat?) + (cons map-1/e string?)) + 10) +]} + +@defproc[(fin-cons/e [x enum?] [y enum?]) enum?]{ + +An @tech{enumeration} of pairs of the values from @racket[x] and +@racket[y]. Both enumerations should be finite. + +@examples[#:eval the-eval +(approximate (fin-cons/e (take/e nat/e 4) (take/e nat/e 5)) 5) +]} + +@defproc[(cons/e [x enum?] [y enum?]) enum?]{ + +An @tech{enumeration} of pairs of the values from @racket[x] and +@racket[y]. + +@examples[#:eval the-eval +(approximate (cons/e (take/e nat/e 4) (take/e nat/e 5)) 5) +(approximate (cons/e nat/e (take/e nat/e 5)) 5) +(approximate (cons/e (take/e nat/e 4) nat/e) 5) +(approximate (cons/e nat/e nat/e) 5) +]} + +@defproc[(elegant-cons/e [x enum?] [y enum?]) enum?]{ + +An @tech{enumeration} of pairs of the values from @racket[x] and +@racket[y]. The enumeration is in a different order than +@racket[cons/e]. Both enumerations should be infinite. + +@examples[#:eval the-eval +(approximate (elegant-cons/e nat/e nat/e) 5) +]} + +@defproc[(traverse/e [f (-> any/c enum?)] [xs (listof any/c)]) enum?]{ + +Constructs an @tech{enumeration} that simulatenously enumerates each +of the enumerations returned by @racket[f] applied to each element of +@racket[xs]. + +@examples[#:eval the-eval +(define traverse-1/e + (traverse/e (λ (x) (map/e (λ (n) (cons x n)) + (λ (y) (cdr y)) + nat/e)) + '("Brian" "Jenny" "Ted" "Ki"))) +(approximate traverse-1/e 5) +(encode traverse-1/e + '(("Brian" . 11) ("Jenny" . 15) ("Ted" . 16) ("Ki" . 7))) +]} + +@defproc[(hash-traverse/e [f (-> any/c enum?)] [xs (listof any/c)]) enum?]{ + +Constructs an @tech{enumeration} that simulatenously enumerates each +of the enumerations returned by @racket[f] applied to each value of +@racket[xs]. + +@examples[#:eval the-eval +(define hash-traverse-1/e + (hash-traverse/e (λ (n) (below/e n)) + (hash "Brian" 5 "Jenny" 15 "Ted" 25 "Ki" 30))) +(approximate hash-traverse-1/e 5) +(encode hash-traverse-1/e + '#hash(("Brian" . 4) ("Jenny" . 1) ("Ted" . 16) ("Ki" . 7))) +]} + +@defproc[(dep/e [a enum?] [b (-> any/c enum?)]) enum?]{ + +Constructs an @tech{enumeration} of pairs of values @racket[a] and +@racket[(b a)]. + +@examples[#:eval the-eval +(define dep-1/e + (dep/e nat/e (λ (a) (below/e a)))) +(approximate dep-1/e 5) +(encode dep-1/e (cons 17 10)) +]} + +@defproc[(dep2/e [n extended-nat?] [a enum?] [b (-> any/c enum?)]) enum?]{ + +Like @racket[dep2/e] but requires the size of the resulting +enumeration be given as @racket[n]. This is more efficient than +@racket[dep/e], particularly when @racket[n] is finite. + +@examples[#:eval the-eval +(define (! n) + (if (zero? n) 1 (* n (! (sub1 n))))) +(define dep2-1/e + (dep2/e (+ (! 1) (! 2) (! 3) (! 4) (! 5)) + (below/e 5) + (λ (a) (below/e a)))) +(approximate dep2-1/e 5) +(encode dep2-1/e (cons 4 3)) +]} + +@defproc[(fold-enum [f (-> (listof a) b enum?)] [bs (listof b)]) enum?]{ + +This is like @racket[foldr], but @racket[f] returns +@tech{enumerations} of @racket[_a]s and assumes that the accumulator +is initialized to @racket['()]. + +@examples[#:eval the-eval +(define fold-enum-1/e + (fold-enum (λ (as b) + (below/e (+ (foldr + 0 as) b))) + (list 1 2 3))) +(approximate fold-enum-1/e 5) +(encode fold-enum-1/e (list 0 1 1)) +]} + +@defproc[(range/e [lo nat?] [hi nat?]) enum?]{ + +An @tech{enumeration} of the naturals between @racket[lo] and @racket[hi]. + +@examples[#:eval the-eval +(approximate (range/e 42 64) 5) +]} + +@defproc[(thunk/e [size extended-nat?] [ep (-> enum?)]) enum?]{ + +A delayed @tech{enumeration} identical to @racket[ep]. This is +typically used with @racket[fix/e]. + +@examples[#:eval the-eval +(approximate (thunk/e +inf.0 (λ () nat/e)) 5) +]} + +@defproc*[([(fix/e [f (-> enum? enum?)]) enum?] + [(fix/e [size extended-nat?] [f (-> enum? enum?)]) enum?])]{ + +An @tech{enumeration} calculated as the fixed-point of @racket[f]. If +@racket[size] is not given, it is assumed to be @racket[+inf.0]. + +@examples[#:eval the-eval +(approximate + (fix/e + +inf.0 + (λ (self) (disj-sum/e (cons (fin/e '()) null?) + (cons (cons/e nat/e self) pair?)))) + 5) +]} + +@defproc*[([(many/e [e enum?]) enum?] + [(many/e [e enum?] [n nat?]) enum?])]{ + +An @tech{enumeration} of lists of length @racket[n] of values +enumerated by @racket[e]. If @racket[n] is not given, lists of any +size are enumerated. + +@examples[#:eval the-eval +(approximate (many/e nat/e) 5) +(approximate (many/e nat/e 5) 5) +]} + +@defproc[(many1/e [e enum?]) enum?]{ + +An @tech{enumeration} of non-empty lists of values enumerated by +@racket[e]. + +@examples[#:eval the-eval +(approximate (many1/e nat/e) 5) +]} + +@defproc[(cantor-vec/e [e enum?] ...) enum?]{ + +An @tech{enumeration} of vectors of values enumerated by the +@racket[e]. + +@examples[#:eval the-eval +(approximate (cantor-vec/e (fin/e "Brian" "Jenny" "Ki" "Ted") + nat/e + (fin/e "Terra" "Locke" "Edgar" "Mash")) + 5) +]} + +@defproc[(vec/e [e enum?] ...) enum?]{ + +An @tech{enumeration} of vectors of values enumerated by the +@racket[e]. + +@examples[#:eval the-eval +(approximate (vec/e (fin/e "Brian" "Jenny" "Ki" "Ted") + nat/e + (fin/e "Terra" "Locke" "Edgar" "Mash")) + 5) +]} + +@defproc[(box-vec/e [e enum?] ...) enum?]{ + +An @tech{enumeration} of vectors of values enumerated by the +@racket[e]. + +@examples[#:eval the-eval +(approximate (box-vec/e (fin/e "Brian" "Jenny" "Ki" "Ted") + nat/e + (fin/e "Terra" "Locke" "Edgar" "Mash")) + 5) +]} + +@defproc[(inf-fin-fair-list/e [e enum?] ...) enum?]{ + +An @tech{enumeration} of lists of values enumerated by the +@racket[e]. + +@examples[#:eval the-eval +(approximate (inf-fin-fair-list/e + (fin/e "Brian" "Jenny" "Ki" "Ted") + nat/e + (fin/e "Terra" "Locke" "Edgar" "Mash")) + 5) +]} + +@defproc[(mixed-box-tuples/e [es (listof enum?)]) enum?]{ + +An @tech{enumeration} of lists of values enumerated by the +enumerations in @racket[es]. + +@examples[#:eval the-eval +(approximate (mixed-box-tuples/e + (list (fin/e "Brian" "Jenny" "Ki" "Ted") + nat/e + (fin/e "Terra" "Locke" "Edgar" "Mash"))) + 5) +]} + +@defproc[(inf-fin-cons/e [x enum?] [y enum?]) enum?]{ + +An @tech{enumeration} of pairs of the values from @racket[x] and +@racket[y]. One of the enumerations must be finite. + +@examples[#:eval the-eval +(approximate (inf-fin-cons/e (take/e nat/e 4) (take/e nat/e 5)) 5) +(approximate (inf-fin-cons/e nat/e (take/e nat/e 5)) 5) +(approximate (inf-fin-cons/e (take/e nat/e 4) nat/e) 5) +]} + +@defproc[(list/e [e enum?] ...) enum?]{ + +An @tech{enumeration} of lists of values enumerated by the +@racket[e]. + +@examples[#:eval the-eval +(approximate (list/e + (fin/e "Brian" "Jenny" "Ki" "Ted") + nat/e + (fin/e "Terra" "Locke" "Edgar" "Mash")) + 5) +]} + +@defproc[(nested-cons-list/e [e enum?] ...) enum?]{ + +An @tech{enumeration} of lists of values enumerated by the +@racket[e]. + +@examples[#:eval the-eval +(approximate (nested-cons-list/e + (fin/e "Brian" "Jenny" "Ki" "Ted") + nat/e + (fin/e "Terra" "Locke" "Edgar" "Mash")) + 5) +]} + +@defproc[(cantor-list/e [e enum?] ...) enum?]{ + +An @tech{enumeration} of lists of values enumerated by the +@racket[e]. + +@examples[#:eval the-eval +(approximate (cantor-list/e + (fin/e "Brian" "Jenny" "Ki" "Ted") + nat/e + (fin/e "Terra" "Locke" "Edgar" "Mash")) + 5) +]} + +@defproc[(box-list/e [e enum?] ...) enum?]{ + +An @tech{enumeration} of lists of values enumerated by the +@racket[e]. + +@examples[#:eval the-eval +(approximate (box-list/e + (fin/e "Brian" "Jenny" "Ki" "Ted") + nat/e + (fin/e "Terra" "Locke" "Edgar" "Mash")) + 5) +]} + +@defproc[(prime-length-box-list/e [es (listof enum?)]) enum?]{ + +An @tech{enumeration} of lists of values enumerated by the +enumerations in @racket[es]. + +@examples[#:eval the-eval +(approximate (prime-length-box-list/e + (list (fin/e "Brian" "Jenny" "Ki" "Ted") + nat/e + (fin/e "Terra" "Locke" "Edgar" "Mash"))) + 5) +]} + +@defproc[(box-tuples/e [k nat?]) enum?]{ + +An @tech{enumeration} of tuples of naturals of length @racket[k]. + +@examples[#:eval the-eval +(approximate (box-tuples/e 3) + 5) +]} + +@defproc[(bounded-list/e [k nat?] [n nat?]) enum?]{ + +An @tech{enumeration} of tuples of naturals up to @racket[n] of length @racket[k]. + +@examples[#:eval the-eval +(approximate (bounded-list/e 3 2) + 5) +]} + +@defproc[(nat+/e [lo nat?]) enum?]{ + +An @tech{enumeration} of tuples of naturals of larger than @racket[lo]. + +@examples[#:eval the-eval +(approximate (nat+/e 42) + 5) +]} + +@defproc[(fail/e [e exn?]) enum?]{ + +An @tech{enumeration} raises @racket[e] if @racket[decode] or +@racket[encode] is called with on. + +@examples[#:eval the-eval +(approximate (fail/e (exn:fail "Don't do that!" (current-continuation-marks))) + 5) +]} + +@defthing[char/e enum?]{ + +An @tech{enumeration} of characters. + +@examples[#:eval the-eval +(approximate char/e 5) +]} + +@defthing[string/e enum?]{ + +An @tech{enumeration} of strings. + +@examples[#:eval the-eval +(approximate string/e 5) +]} + +@defthing[from-1/e enum?]{ + +An @tech{enumeration} of naturals starting from @racket[1]. + +@examples[#:eval the-eval +(approximate from-1/e 5) +]} + +@defthing[integer/e enum?]{ + +An @tech{enumeration} of integers. + +@examples[#:eval the-eval +(approximate integer/e 5) +]} + +@defthing[float/e enum?]{ + +An @tech{enumeration} of flonums. + +@examples[#:eval the-eval +(approximate float/e 5) +]} + +@defthing[real/e enum?]{ + +An @tech{enumeration} of reals. + +@examples[#:eval the-eval +(approximate real/e 5) +]} + +@defthing[non-real/e enum?]{ + +An @tech{enumeration} of non-real numbers. + +@examples[#:eval the-eval +(approximate non-real/e 5) +]} + +@defthing[num/e enum?]{ + +An @tech{enumeration} of numbers. + +@examples[#:eval the-eval +(approximate num/e 5) +]} + +@defthing[bool/e enum?]{ + +An @tech{enumeration} of booleans. + +@examples[#:eval the-eval +(to-list bool/e) +]} + +@defthing[symbol/e enum?]{ + +An @tech{enumeration} of symbols. + +@examples[#:eval the-eval +(approximate symbol/e 5) +]} + +@defthing[base/e enum?]{ + +An @tech{enumeration} of atomic Racket values. + +@examples[#:eval the-eval +(approximate base/e 5) +]} + +@defthing[any/e enum?]{ + +An @tech{enumeration} of S-expressions. + +@examples[#:eval the-eval +(approximate any/e 5) +]} + +@close-eval[the-eval] diff --git a/pkgs/data-pkgs/data-lib/data/enumerate.rkt b/pkgs/data-pkgs/data-lib/data/enumerate.rkt index 03e93a60ce..72b6bf8cc6 100644 --- a/pkgs/data-pkgs/data-lib/data/enumerate.rkt +++ b/pkgs/data-pkgs/data-lib/data/enumerate.rkt @@ -78,6 +78,9 @@ [const/e (-> any/c enum?)] + [from-list/e + (-> list? + enum?)] [fin/e (->* () #:rest list? enum?)]