Skip to content

Commit af5086f

Browse files
more writing
1 parent 9f52857 commit af5086f

File tree

1 file changed

+30
-25
lines changed

1 file changed

+30
-25
lines changed

docs/Manual.md

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -384,51 +384,57 @@ conformsToSpec :: HasSpec a => a -> Specification a -> Bool
384384

385385
## How we solve the constraints
386386

387+
Before we continue delving into how we use the library and the finer points
388+
surrounding generics and overloading it's worth-while to take a detour into how
389+
we solve constraints. Understanding and internalising this will be helpful when
390+
writing anything but the simplest generators.
391+
387392
The strategy for generating things from `Pred`s is relatively straightforward
388393
and relies on one key fact: any constraint that has only one free variable `x`
389394
and where `x` occurs only once can be turned into a `Specification` for `x`.
390395

391-
We say that such constraints _define_ `x` and given a set of constraints `ps`
392-
and a variable `x` we can split `ps` into the constraints that define `x` and
393-
any constraints that don't. We can then generate a value from `x` by computing
394-
a spec for each defining constraint in `ps` and using the `Semigroup` structure
395-
of `Specification`s to combine them and give them to `genFromSpecT`. Once we obtain a
396-
value for `x` we can substitute this value in all other constraints and pick
397-
another variable to solve.
396+
We say that such constraints _define_ `x` (alt. are _defining_ for `x`) and
397+
given a set of constraints `ps` and a variable `x` we can split `ps` into the
398+
constraints that define `x` and any constraints that don't. We can then
399+
generate a value from `x` by computing a spec for each _defining constraint_ in
400+
`ps` and using the `Semigroup` structure of `Specification`s to combine them
401+
and give them to `genFromSpecT`. Once we obtain a value for `x` we can
402+
substitute this value in all other constraints and pick another variable to
403+
solve.
398404

399405
For example, given the following constraints on integers `x` and `y`
400406

401407
```
402-
x <. 10
403-
3 <=. x
404-
y <. x
408+
x <. 10
409+
3 <=. x
410+
y <. x
405411
```
406412
407413
we see that `x <. 10` and `3 <=. x.` are defining constraints for `x` and there
408-
are no defining constraints for `y`. We compute a `Specification` for `x` for each
414+
are no defining constraints for `y` (yet!). We compute a `Specification` for `x` for each
409415
constraint, in this case `x <. 10` turns into something like `(-∞,10)` and
410416
`3 <=. x` turns into `[3, ∞)`. We combine the specs to form `[3, 10)` from which we
411417
can generate a value, e.g. 4 (chosen by fair dice roll). We then substitute
412418
`[x := 4]` in the remaining constraints and obtain `y <. 4`, giving us a defining
413-
constraint for `y`.
419+
constraint for `y`. We then repeat the process for `y`, giving us a specification
420+
like `(-∞,4)` for `y`, from which we can generate a value.
414421
415422
### How to pick the variable order
416423
417424
At this point it should be relatively clear that the order we pick for the
418425
variables matters a great deal. If we choose to generate `y` before `x` in our
419426
example we will have no defining constraints for `y` and so we pick a value for
420-
it freely. But that renders `x` unsolvable if `y > 9` - which will result in
427+
it freely. But that may render `x` unsolvable if `y > 9` - which will result in
421428
the generator failing to generate a value (one could consider backtracking, but
422-
that is very computationally expensive so _relying_ on it would probably not be
423-
wise).
429+
that is very computationally expensive so _relying_ on it would not be wise).
424430
425431
Computing a good choice of variable order that leaves the least room for error
426-
is obviously undecidable and difficult and we choose instead an explicit
427-
syntax-directed variable order. Specifically, variable dependency in terms is
428-
_left-to-right_, meaning that the variables in `x + y <. z` will be solved in
429-
the order `z -> y -> x`. On top of that there is a constraint `dependsOn y x`
430-
that allows you to overwrite the order of two variables. Consequently, the
431-
following constraints will be solved in the order `z -> x -> y`:
432+
is difficult and we choose instead an explicit syntax-directed variable order.
433+
Specifically, variable dependency in terms is _left-to-right_, meaning that the
434+
variables in `x + y <. z` will be solved in the order `z -> y -> x`. On top of
435+
that there is a constraint `dependsOn y x` that allows you to overwrite the
436+
order of two variables. Consequently, the following constraints will be solved
437+
in the order `z -> x -> y`:
432438
433439
```
434440
x + y <. z
@@ -479,7 +485,7 @@ The principal problem above is that information that is present in the
479485
constraints is lost, which would force us to rely on a `suchThat` approach to
480486
generation - which will become very slow as constraint systems grow.
481487
482-
### Using Match to introduce new variables for subcomponents
488+
### Using `match` to introduce new variables for subcomponents
483489
484490
A solution to the total definition requirement is to *introduce more variables*.
485491
We can rewrite the problematic `fst p <. snd p` example below as:
@@ -505,8 +511,8 @@ constraints - these need to be bound somewhere - and (2) the order of
505511
`fst_ p = x` is important, `p` depends on `x`, and not the other way
506512
around.
507513
508-
To do both of these things at the same time we use the `match` construct
509-
to the language:
514+
To do both of these things at the same time we use the `match` construct to the
515+
language:
510516
511517
```
512518
match :: Term (a,b) -> (Term a -> Term b -> Pred) -> Pred
@@ -531,7 +537,6 @@ match p $ \ x y -> x <. y
531537
532538
In previous sections we provided some types for several of the library functions: `constrained`, `match`,
533539
534-
535540
```haskell
536541
constrained :: HasSpec a => (Term a -> Pred) -> Specification a
537542

0 commit comments

Comments
 (0)