1 | ;
|
2 |
|
3 | var show = require("./show.js");
|
4 |
|
5 | /**
|
6 | ### Arbitrary data
|
7 | */
|
8 |
|
9 | // Blessing: i.e adding prototype
|
10 | /* eslint-disable no-use-before-define */
|
11 | function arbitraryProtoSMap(f, g, newShow) {
|
12 | /* jshint validthis:true */
|
13 | var arb = this; // eslint-disable-line no-invalid-this
|
14 | return arbitraryBless({
|
15 | generator: arb.generator.map(f),
|
16 | shrink: arb.shrink.smap(f, g),
|
17 | show: newShow || show.def,
|
18 | });
|
19 | }
|
20 | /* eslint-enable no-use-before-define */
|
21 |
|
22 | /**
|
23 | - `.smap(f: a -> b, g: b -> a, newShow: (b -> string)?): arbitrary b`
|
24 |
|
25 | Transform `arbitrary a` into `arbitrary b`. For example:
|
26 |
|
27 | `g` should be a [right inverse](http://en.wikipedia.org/wiki/Surjective_function#Surjections_as_right_invertible_functions) of `f`, but doesn't need to be complete inverse.
|
28 | i.e. i.e. `f` doesn't need to be invertible, only surjective.
|
29 |
|
30 | ```js
|
31 | var positiveIntegersArb = nat.smap(
|
32 | function (x) { return x + 1; },
|
33 | function (x) { return x - 1; });
|
34 | ```
|
35 |
|
36 | ```js
|
37 | var setNatArb = jsc.array(jsc.nat).smap(_.uniq, _.identity);
|
38 | ```
|
39 |
|
40 | Right inverse means that *f(g(y)) = y* for all *y* in *Y*. Here *Y* is a type of **arrays of unique natural numbers**. For them
|
41 | ```js
|
42 | _.uniq(_.identity(y)) = _.uniq(y) = y
|
43 | ```
|
44 |
|
45 | Opposite: *g(f(x))* for all *x* in *X*, doesn't need to hold. *X* is **arrays of natural numbers**:
|
46 | ```js
|
47 | _.identity(_uniq([0, 0])) = [0]] != [0, 0]
|
48 | ```
|
49 |
|
50 | We need an inverse for shrinking, and there right inverse is enough. We can always *pull back* `smap`ped value, shrink the preimage, and *map* or *push forward* shrunken preimages again.
|
51 | */
|
52 | function arbitraryBless(arb) {
|
53 | arb.smap = arbitraryProtoSMap;
|
54 | return arb;
|
55 | }
|
56 |
|
57 | module.exports = arbitraryBless;
|