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].
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.