@@ -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+
387392The strategy for generating things from `Pred `s is relatively straightforward
388393and relies on one key fact: any constraint that has only one free variable `x`
389394and 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
399405For 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
407413we 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
409415constraint, 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
411417can 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
417424At this point it should be relatively clear that the order we pick for the
418425variables matters a great deal. If we choose to generate `y` before `x` in our
419426example 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
421428the 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
425431Computing 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
479485constraints is lost, which would force us to rely on a `suchThat` approach to
480486generation - 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
484490A solution to the total definition requirement is to *introduce more variables*.
485491We 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
506512around.
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```
512518match :: Term (a,b) -> (Term a -> Term b -> Pred) -> Pred
@@ -531,7 +537,6 @@ match p $ \ x y -> x <. y
531537
532538In previous sections we provided some types for several of the library functions: `constrained`, `match`,
533539
534-
535540```haskell
536541constrained :: HasSpec a => (Term a -> Pred) -> Specification a
537542
0 commit comments