Helpers¶
Forge and Frglet provide a number of built-in helpers to ease your work in the language.
Sequences¶
A sequence is a field f of the form f: pfunc Int -> A (where A can be any sig) such that:
fis a partial function (i.e., eachInthas at most one corresponding entry);- no index
Intis less than zero; and - indexes are contiguous (e.g., if there are entries at index
1and index3, there must be one at index2).
You can think of sequences as roughly analogous to fixed-size arrays in a language like Java. To tell Forge that a partial-function field f is a sequence, use the isSeqOf predicate.
Hint: make sure that you use isSeqOf in any test or run that you want to enforce that f is a sequence. The isSeqOf predicate is just another constraint: it's not a persistent declaration like pfunc is.
isSeqOf¶
isSeqOf[f, A]: a predicate that holds if and only iffis a sequence of values inA.
Sequence Helpers¶
The following helpers are also available, but should only be used when f is a sequence:
Sequence Helper Functions:¶
seqFirst[f]: returns the first element off, i.e.f[0].seqLast[f]: returns the last element off.indsOf[f, e]: returns all the indices ofeinf.idxOf[f, e]: returns the first index ofeinf.lastIdxOf[f, e]: returns the last index ofeinf.elems[f]: returns all the elements off.inds[f]: returns all the indices off.
Sequence Helper Predicates:¶
isEmpty[f]: true if and only if sequencefis empty.hasDups[f]: true if and only if sequencefhas duplicates (i.e., there are at least two indices that point to the same value).
Reachability¶
Forge provides a convenient way to speak of an object being reachable via fields of other objects.
reachable[a, b, f]: objectais reachable frombthrough recursively applying fieldf. This predicate only works ifa.fis well-defined.reachable[a, b, f1, f2, ...]: an extended version ofreachablewhich supports using more than one field to reachafromb.
The extended version of reachable is useful if you wish to model, e.g., binary trees where nodes have a left and right field. In such a model, if you want to quantify over all descendents of a parent node, you might write all n: Node | reachable[n, parent, left, right].
Order matters!
Beware: the order of arguments in reachable matters! The first argument is the object to be reached, and the second argument is the starting object. Getting these reversed is a common source of errors.
The value none is reachable from anything
Beware: if you pass something that might be none as the first argument of reachable, in such cases reachable will evaluate to true. E.g., reachable[p.spouse, p, father] will evaluate to true if p happens to be unmarried.