Skip to content

Commit 172ae54

Browse files
more cleanup pass
1 parent bd17e08 commit 172ae54

File tree

1 file changed

+41
-31
lines changed

1 file changed

+41
-31
lines changed

docs/Manual.md

Lines changed: 41 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ and all the examples in this file can be found
5353

5454
## Constrained Generators is a First-Order Logic
5555

56-
5756
A First-order typed logic (FOTL) has 4 components, where each component uses types to ensure well-formedness.
5857

5958
1. **Terms** consisting of
@@ -75,41 +74,45 @@ and _generate values_: `gen :: Specification T -> Gen T`. This supports
7574
property based testing where a completely random set of values may not be
7675
useful without having to write explicit random generation logic.
7776

78-
7977
## Design Goals of the Library
8078

8179
The system was designed to have several important properties
8280

83-
1. A Specification determines a `QuickCheck` generator for generating random values subject to constraints.
84-
2. A Specification determines a check that a particular value meets all the specifications constraints.
85-
3. If a Specification is over-constrained, the system tries to explain where the conflict occurs.
86-
4. The system is compositional so specifications can be re-used
81+
1. A Specification determines a `QuickCheck` generator for generating random
82+
values subject to constraints.
83+
2. A Specification determines a check that a particular value meets all the
84+
specifications constraints.
85+
3. The system is compositional so specifications can be re-used
86+
4. If a Specification is over-constrained, the system tries to explain where
87+
the conflict occurs.
8788
5. The system is extensible so that it can accomodate new types and functions.
8889

89-
The first part is implemented by the function `genFromSpec`
90-
90+
Point (1) is implemented by the following function
9191
```haskell
9292
genFromSpec :: HasSpec a => Specification a -> QuickCheck.Gen a
9393
```
94-
95-
The second is implemented by the function `conformsToSpec`
96-
94+
and (2) by this function:
9795
```haskell
9896
conformsToSpec :: HasSpec a => a -> Specification a -> Bool
9997
```
100-
101-
The third is embodied by the error messages when solving a constraint fails
98+
(3) is captured succinctly by:
99+
```haskell
100+
instance Monoid (Specification t) -- This is far from the whole story...
101+
```
102+
while (4) is embodied primarily in the error messages given when `genFromSpec`
103+
fails. Point (5) meanwhile requires a bit of explanation and will in no small part
104+
be the subject of this document.
102105

103106
The **Constrained Generators** system is implemented as an embeded domain
104107
specific language in Haskell. The Terms, Predicates, Connectives, and
105108
Quantifiers of the first order logic are embedded into three Haskell datatypes
106109
(`Specification t`, `Term t`, and `Pred`). There is a rich (extendable) library
107110
of Haskell functions that can be used to define and construct values of these
108-
types. The library is implemented in a such a way, that the four parts of the
109-
logic are defined in ways that are similar to Haskell expressions with type
110-
Bool.
111+
types. The library is implemented in a such a way, that the four parts of the
112+
logic are defined in ways that are similar (but different in important ways we
113+
will cover below) to Haskell expressions of type Bool.
111114

112-
Let us look at a simple example, and study how this is done. Below is a Haskell
115+
Let us look at a simple example and study how this is done. Below is a Haskell
113116
declaration that defines a specification of a pair of Int (`p`) , subject to
114117
the constraint that the first component (`x`) is less than or equal to the
115118
second component (`y`) plus 2
@@ -124,9 +127,9 @@ leqPair = constrained $ \ p ->
124127
The library uses Haskell lambda expressions to introduce variables in the Term
125128
language of the system, and Haskell functions to build `Term`s and
126129
`Predicate`s. The Haskell function `lit` takes Haskell values and turns them
127-
into constants in the Term language. We give monomorphic types to the Haskell
128-
functions used in the above definitions. We discuss more general types in a
129-
[later section](#overloaded).
130+
into constants in the Term language. We'll give partially monomorphized types
131+
to the Haskell functions used in the above definitions. We discuss more general
132+
types in a [later section](#overloaded).
130133

131134
```haskell
132135
constrained :: HasSpec a => (Term a -> Pred) -> Specification a
@@ -140,13 +143,15 @@ assert :: Term Bool -> Pred
140143
(<=.) :: OrdLike a => Term a -> Term a -> Term Bool
141144
```
142145

143-
The Haskell Constraint `HasSpec a` states that the type `a` has been admitted to the system as one of the types
144-
that can be subject to constraints. The system comes with a large set of `HasSpec` instances, including ones for:
146+
The Haskell Constraint `HasSpec a` states that the type `a` has been admitted
147+
to the system as one of the types that can be subject to constraints. The
148+
system comes with a large set of `HasSpec` instances for types in `base` and
149+
`containers`, including ones for:
145150

146151
1. Bool
147152
2. Tuples
148153
3. Sums
149-
4. Numeric types (Int, Integer, Natural, Int8, Int16, Int32, Int64, Word8, Word16, Word32, Word64)
154+
4. Numeric types (Int, Integer, Natural, Int/Word{8,16,32,64})
150155
5. Lists
151156
6. Maps
152157
7. Sets
@@ -157,19 +162,24 @@ that can be subject to constraints. The system comes with a large set of `HasSpe
157162

158163
## HasSpec instances
159164

160-
`HasSpec` instances can always be added to admit more types. Any type with a `GHC.Generics(Generic)` instance can be
161-
given a default instance by using its Sum-of-Products generic definition. In the Cardano Ledger System
162-
over 200 types in the Ledger code base have been given `HasSpec` instances, either by using the `GHC.Generics` path, or by writing the instances by hand.
165+
`HasSpec` instances can always be added to admit more types. Any type with a
166+
`Generic` instance can be given a default instance by using its generic
167+
definition - provided that the types it uses have `HasSpec` instances. In the
168+
Cardano Ledger System over 200 types in the Ledger code base have been given
169+
`HasSpec` instances, either by using the `GHC.Generics` path, or by writing the
170+
instances by hand (more on this later).
163171

164172
## Building logic specifications using Haskell functions
165173

166-
Note that `constrained` and `match` take functions, which abstract over terms, and return `Specification` and `Pred`.
167-
Using the library functions, variables in the Term language are always introduced using Haskell lambda abstractions. And the library
168-
functions combine these into Terms, Preds, and Specifications.
174+
Note that `constrained` and `match` take functions, which abstract over terms,
175+
and return `Specification` and `Pred`. Using the library functions, variables
176+
in the Term language are always introduced using Haskell lambda abstractions.
177+
And the library functions combine these into Terms, Preds, and Specifications.
169178

170179
## Another example using conjunction and simple arithmetic
171180

172-
Suppose we want to put more than one simple condition on the pair of Ints. We would do that using the connective `And` that converts a `[Pred]` into a `Pred`
181+
Suppose we want to put more than one simple condition on the pair of Ints. We
182+
would do that using the connective `And` that converts a `[Pred]` into a `Pred`
173183

174184
```haskell
175185
sumPair :: Specification (Int, Int)
@@ -183,7 +193,7 @@ sumPair = constrained $ \p ->
183193
```
184194

185195
This example also re-illustrates that `(Term Int)` has a (partial) Num instance, and that we can constrain
186-
multiple (different) variables using simple `Num` methods (`(+)`, `(-)`, and `negate`). Note also
196+
multiple (different) variables using simple `Num` methods (`(+)`, `(-)`, `(*)`, and `negate`). Note also
187197
the operator: `(==.) :: (Eq n, HasSpec n) => Term n -> Term n -> Term Bool`
188198

189199
## Function Symbols

0 commit comments

Comments
 (0)