You are looking at historical revision 30694 of this page. It may differ significantly from its current revision.

data-generators

Requirements

random-bsd, numbers

Repository

https://bitbucket.org/certainty/data-generators/overview

Authors

David Krentzlin

Introduction

This egg provides primitives and combinators to generate random data. That may be useful for testing or other occasions where you just need a way to quickly generate data.

Examples

data-generators

(use json data-generators)

;; generate a json document
(define (gen-json-doc #!optional (nesting 5))
  (generator
   (with-output-to-string
     (lambda ()  (json-write (<- (gen-json-value nesting)))))))

;; this is the only tricky part
;; we need to stop the recursion at a certain level of nesting and yet
;; we want to reduce the construction of generators to a minimum
(define (gen-json-value nesting)
  (let ((scalar (gen-json-scalar)))
    (if (positive? nesting)
        (gen-sample-of (gen-json-complex (sub1 nesting)) scalar)
        scalar)))

(define (gen-json-scalar)
  (gen-sample-of (gen-json-null) (gen-json-string) (gen-json-number)))

(define (gen-json-string)
  (with-size (range 0 20)
    (gen-string-of (gen-char #\A #\z))))

(define (gen-json-null)
  (gen-constant (void)))

(define (gen-json-number)
  (gen-sample-of (gen-fixnum) (gen-real)))

(define (gen-json-complex nesting)
  (gen-sample-of (gen-json-object (sub1 nesting)) (gen-json-array (sub1 nesting))))

(define (gen-json-object nesting)
  (gen-vector-of (gen-pair-of (gen-json-string) (gen-json-value (sub1 nesting)))))

(define (gen-json-array nesting)
  (gen-list-of (gen-json-value (sub1 nesting))))

;; now let's print our documents
(with-size (range 0 20)
  (gen-for-each 10 print (gen-json-doc 10)))

data-generators-literals

(use data-generators data-generators-literals)

;; create a generator using the generator literal 
(print (<- #g[0 .. 100]))

;; create a generator using the range literal
(print (<- (gen-list-of (gen-fixnum #i[0 ... 100])))

API

Generators

A generator is a means to create random values that possibly adhere to some constraints. By nature a generator represents an infinite stream of random values.

[syntax] (generator ?body ...)

Creates a new generator. You can use this to define your own generators.

Example:

(define (my-gen start)
 (generator (+ start 42))

(<- (my-gen 10)) ;=> 52

Extracting data from generators

[procedure] (<- gen)

Invokes the generator gen once and returns that value.

[procedure] (<- amount gen)

Invokes the generator gen amount times and returns a list of values

[procedure] (gen-for-each n proc gen)

Invokes the generator gen n times and applies proc to each value in turn. proc must be a procedure that takes two arguments. The first argument will be the value and the second argument will be the round in which the value was generated.

Ranges

Many generators accept a range argument that specifies the upper and lower bounds. You can use the following procedures to work with ranges.

[procedure] (range lower upper)

Creates a range that covers values from lower to upper. There are three variations of this:

Generic generator

The library provides a generic generator procedure that is able to build the correct generator based on the type of the supplied arguments.

[procedure] (gen lower upper)

Creates a generator that can be created for the given argument types. Currently supported types are:

[procedure] (gen range)

Creates a generator that can be created for the given range. It dispatches on the type of the lower bound. Currently supported types are:

[procedure] (register-generator-for-type! type? gen)

Registers a type-predicate with a generator. When the generic generator procedure gen is invoked, it will dispatch on the first argument using the registered type-predicates.

Parameters

[parameter] gen-current-fixnum-min

The smallest fixnum that should be generated.

[parameter] gen-current-fixnum-max

The biggest fixnum that should be generated

Primitives

[procedure] (gen-constant value)

Generator that always returns value.

[procedure] (fixnums ...)

Alias for gen-fixnum.

[procedure] (gen-fixnum)

Generator for a fixnum between gen-current-fixnum-min and gen-current-fixnum-max.

[procedure] (gen-fixnum range)

Generator for a fixnum within the given range

[procedure] (gen-fixnum lower-bound upper-bound)

Generator for a fixnum between lower-bound and upper-bound

[procedure] (odd-fixnums ...)

Alias for gen-odd-fixnum.

[procedure] (gen-odd-fixnum ...)

This generator supports all the variations for gen-fixnum but it will only yield odd numbers

[procedure] (even-fixnums ...)

Alias for gen-even-fixnum.

[procedure] (gen-even-fixnum ...)

This generator supports all the variations for gen-fixnum but it will only yield even numbers

[procedure] (gen-int8)

Generator for a fixnum between -127 and 127.

[procedure] (gen-uint8)

Generator for a fixnum between 0 and 255.

[procedure] (gen-int16)

Generator for a fixnum between -32767 and 3276.

[procedure] (gen-uint16)

Generator for a fixnum between 0 and 65535.

[procedure] (gen-int32)

Generator for a fixnum between -2147483647 and 2147483647.

[procedure] (gen-uint32)

Generator for a fixnum between 0 and 4294967295.

[procedure] (gen-int64)

Generator for a fixnum between -9223372036854775807 and 9223372036854775807.

[procedure] (gen-uint64)

Generator for a fixnum between 0 and 18446744073709551615.

[procedure] (gen-real)

Generator for a real number between 0.0 and 1.0.

[procedure] (gen-real range)

Generator for a real number in the given range.

[procedure] (gen-real lower-bound upper-bound)

Generator for a real number between lower-bound and upper-bound.

[procedure] (gen-flonum)

Generator for a flonum between 0.0 and 1.0 or one of the special flonums +nan.0 +inf.0 and -inf.0.

[procedure] (gen-flonum range)

Generator for a flonum in the given range.

[procedure] (gen-flonum lower-bound upper-bound)

Generator for a flonum between lower-bound and upper-bound.

[procedure] (gen-rational)

Generator for a rational number

[procedure] (gen-rational nom-gen denom-gen)

Generator for a rational number where the nominator is generated with nom-gen and the denominator is generated with denom-gen.

[procedure] (chars ...)

Alias for gen-char.

[procedure] (gen-char)

Generator for a character from char-set:graphic.

[procedure] (gen-char charset)

Generator for a character from the char-set charset.

[procedure] (gen-char range)

Generator for a character in the given range.

[procedure] (gen-char lower-bound upper-bound)

Generator for a character from the char-set build from lower-bound to upper-bound. lower-bound must be <= upper-bound as compared with char<=?.

Example:

(gen-char #\a #\z)
[procedure] (booleans)

Alias for gen-bool.

[procedure] (gen-bool)

Generator for a random boolean value

[procedure] (gen-procedure)

Generator for a procedure. This is equivalent to (gen-procedure (<- (gen-fixnum 0 max-arity)) (gen-bool)).

[procedure] (gen-procedure arity return-gen)

Generator that generates procedures with the given arity with 0 <= arity <= max-arity. max-arity is currently 20. The procedures that are generated return a value that is created by invoking return-gen.

[procedure] (gen-sample candidates)

Generator that draws a random sample from the list of candidates.

[procedure] (gen-series)

Generator that returns values from the series starting at gen-current-fixnum-min till gen-current-fixnum-max by applying add1 in each step.

Example:

;; create lists with increasing size from 1 to 10
(<- 10 (gen-list-of (fixnums) (gen-series 1 10 add1)))
[procedure] (gen-series start end step)

Generator that generates values from start to end with steps as specified by the one-argument-procedure step. The step procedure gets the current value during each application of the generator and must return the next possible value. The generator automatically wraps around and starts over if the end of the series has been reached.

Combinators

[parameter] (gen-current-default-size)

A generator that must return a fixnum. It's used to determine the size for generators that can have a length. This defaults to (gen-uint8).

[procedure] (gen-values-of . gens)

Generator that returns multiple values. Each value is generated with the given generators

[procedure] (gen-pair-of car-gen cdr-gen)

Generator for a pair where the car is generated with car-gen and the cdr is generated with with cdr-gen.

[procedure] (gen-sample-of . gens)

Generator that draws a random generator from the list of possible generators and invokes it once.

[procedure] (gen-tuple-of . gens)

Generator for a tuple where each element is generated by the given generators.

[procedure] (gen-string ...)

Alias for gen-string-of.

[procedure] (gen-string-of char-gen #!optional (size (gen-current-default-size)))

Generator for a string where each character is generated from char-gen. The size parameter specifies the size of the strings that are generated. It is expected to be a thunk that returns the size as a fixnum. See with-size for a more convenient way to adjust this.

[procedure] (gen-symbol ...)

Alias for gen-symbol-of

[procedure] (gen-symbol-of #!optional (char-gen (gen-char char-set:letter+digit)) (size (gen-current-default-size)))

Generator for a symbol where each character is generated from char-gen. The size parameter specifies the size of the strings that are generated. It is expected to be a thunk that returns the size as a fixnum. See with-size for a more convenient way to adjust this.

[procedure] (gen-keyword ...)

Alias for gen-keyword-of

[procedure] (gen-keyword-of #!optional (char-gen (gen-char char-set:letter+digit)) (size (gen-current-default-size)))

Generator for a keyword where each character is generated from char-gen. The size parameter specifies the size of the strings that are generated. It is expected to be a thunk that returns the size as a fixnum. See with-size for a more convenient way to adjust this.

[procedure] (gen-list-of gen #!optional (size (gen-current-default-size)))

Generator for a list where each element is generated with the given generator gen. The size parameter specifies the size of the list that is generated. It is expected to be a thunk that returns the size as a fixnum. See with-size for a more convenient way to adjust this.

[procedure] (gen-alist-of car-gen cdr-gen #!optional (size (gen-current-default-size)))

Generator for an alist where each car is generated with car-gen and each cdr is generated with with cdr-gen. The size parameter specifies the size of the list that is generated. It is expected to be a thunk that returns the size as a fixnum. See with-size for a more convenient way to adjust this.

[procedure] (gen-vector-of gen #!optional (size (gen-current-default-size)))

Generator for a vector where each element is generated with the given generator gen. The size parameter specifies the size of the vector that is generated. It is expected to be a thunk that returns the size as a fixnum. See with-size for a more convenient way to adjust this.

[procedure] (gen-hash-table-of key-gen value-gen #!optional (size (gen-current-default-size)) (equal? eq?))

Generator for a hash-table where each key is generated by key-gen and each value is generated by value-gen. The size parameter specifies the size of the hash-table that is generated. The equal? parameter is passed directly to make-hash-table. It is expected to be a thunk that returns the size as a fixnum. See with-size for a more convenient way to adjust this.

[procedure] (gen-record ctor . slot-gens)

Generator for a record that is created with the given ctor where each slot is generated with the given slot-gens.

[procedure] (gen-transform transformer gen)

Generator that retrieves values from gen and applies transformer to this value.

;; gen positive fixnums

(gen-transform abs (fixnums))
[syntax] (with-size size-spec ...)

Use this to constrain the size of the data generated by the combinators. size-spec is either a fixnum a range or a generator. If it is a fixnum all data will be generated with the size equal to that fixnum. If it is a range, all data will be generated with a size that lies within that range. If it's a generator, this generator is expected to return the size.

Networking generators

In order to use these you need to (use data-generators-net).

[procedure] (gen-ipv4-address)

Creates a generator that returns a string representing a dotted quad ipv4 address.

Defining your own generators

To define your own generators you can use the generator-syntax.

(define (gen-foo) (generator "foo"))

(with-size 3 (gen-list-of (gen-foo))) ;=> ("foo" "foo" "foo")

Reader extensions

Optionally you can use data-generators-literals to use reader-extensions that allow you to create ranges and generators.

[syntax] #i[x .. y]

Creates a range from x to y inclusive.

[syntax] #i[ .. y]

Creates a range from (gen-current-fixnum-min) to y inclusive.

[syntax] #i[x .. ]

Creates a range from x to (gen-current-fixnum-max) inclusive.

[syntax] #i[x ... y]

Creates a range from x to y exclusive.

[syntax] #i[ ... y]

Creates a range from (gen-current-fixnum-min) to y exclusive.

[syntax] #i[x ... ]

Creates a range from x to (gen-current-fixnum-max) exclusive.

[syntax] #g[range-exp]

Creates a generator by applying gen to the given range-expression. The range-expression is the same that the #i[]-reader-macro supports. It expands to (gen range-expression).

Example:

(use data-generators data-generators-literals)

(<- #g[1 .. 10])
(<- #g[#\a ... #\z])
(<- #g[1.0 .. 10.3])

See also

For a very exhaustive and systematic approach to all kinds of random sources see: srfi-27

License

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.
A full copy of the GPL license can be found at
<http://www.gnu.org/licenses/>.