On this page:
2.1 Semantics
rule-struct
evaluate-rule
backtrack
exn:  backtrack
make-rule-parameter
2.2 Syntax
rule
define-rule
simple-rule
define-simple-rule
~>
2.3 Preconditions
need
once
n-times
2.4 Sequences
cycle
7.6

2 The jen Reference

 (require jen) package: jen-lib
jen reprovides all of the modules in this package.

2.1 Semantics

 (require jen/base) package: jen-lib
jen/base provides the low-level semantics and tools for working with rules and clauses.

struct

(struct rule-struct (clauses))

  clauses : (hash/c (-> any/c) (-> exact-nonnegative-integer?))
The rule-struct structure represents procedural generation rules, the central concept of this library.

clauses is a hash where each mapping represents a clause that may be randomly chosen. The key is the try thunk, a nullary procedure that’s applied when the clause is chosen; and the value is the weight thunk, also a nullary procedure, one that’s applied to determine the clause’s likelihood of being chosen.

Applying a rule-struct value is the same as applying evaluate-rule to it.

procedure

(evaluate-rule a-rule-struct    
  [#:default default-value])  any/c
  a-rule-struct : rule-struct?
  default-value : any/c = an opaque value
Evaluates a rule as follows:

The rule’s clauses’ weight thunks are all evaluated, then try thunks are evaluated at random, weighted by their corresponding computed weight, until one of them succeeds, i.e., doesn’t backtrack. (See backtrack and exn:backtrack.) If a clause succeeds, evaluate-rule returns the result of its try thunk. If no clause succeeds, then the entire rule backtracks.

The probability of a clause being chosen is its computed weight divided by the total of all clauses’ computed weights.

If a #:default argument is provided, it will be the return value in case the rule would have otherwise backtracked. This is useful for keeping the backtrack signal from bubbling to the top when a rule is being evaluated outside of any other rule. (See exn:backtrack for how to deal with it in general.)

procedure

(backtrack [message])  none/c

  message : string? = #f
Signals a backtrack by raising an exn:backtrack value.

If message is provided, it will be used to provide a more descriptive error message for debugging purposes.

exn:backtrack represents the backtrack signal.

Although usually unnecessary (see evaluate-rule), it’s possible to catch a backtrack manually by installing an exn:backtrack? handler. For example:

(define-rule start)
 
(with-handlers ((exn:backtrack? (const "It backtracked!")))
  (start))

"It backtracked!"

procedure

(make-rule-parameter [initial-value])  parameter?

  initial-value : any/c = #f
Makes a rule parameter, which, whenever a clause backtracks, reverts its value to whatever it was just before the clause was tried.

This is useful for tagging rules with additional state that needs to remain consistent with respect to clauses being tried but failing.

2.2 Syntax

 (require jen/syntax) package: jen-lib
jen/syntax provides clean syntax on top of the rule primitives to make it easier to work with them in common cases.

syntax

(rule clause ...)

 
clause = proc-expr maybe-weight
     
maybe-weight = 
  | #:weight weight-expr
Produces a rule whose clauses are given by clauses.

For each clause, proc-expr is evaluated immediately to obtain the clause’s try thunk, while weight-expr (by default, 1) becomes the body of the weight thunk and thus is evaluated only when the rule is.

syntax

(define-rule id rest ...)

Shorthand for (define id (rule rest ...)).

syntax

(simple-rule expr ...)

Shorthand for (rule (thunk expr) ...).

This is useful when each of your clauses only needs to be a single expression without complex logic, allowing you to omit ~> or other procedure-producing forms.

syntax

(define-simple-rule id rest ...)

Shorthand for (define id (simple-rule rest ...)).

syntax

(~> expr ... maybe-combiner)

 
maybe-combiner = 
  | #:combiner combiner-expr
Returns a procedure taking no arguments and returning the result of applying combiner-expr (by default, ~a) to each expr, but filtering out any values satisfying void?. This is meant for use with rule or define-rule but produces ordinary procedures, much like thunk but slightly more specialized.

The void?-filtering behavior is particularly useful alongside jen/preconditions, which contains procedures and forms that affect clause evaluation and return (void). If this turns out to be undesirable for a given use case, it’s still possible to use thunk with define-rule.

2.3 Preconditions

jen/preconditions provides support for clause preconditions, by which a clause can decide not to execute if its conditions aren’t met.

procedure

(need condition)  void?

  condition : any/c
Returns a void? value when condition is true; otherwise signals a backtrack by calling (backtrack).

syntax

(once)

Shorthand for (n-times 1).

syntax

(n-times n)

 
  n : natural?
During the current top-level rule evaluation, if the clause containing the call site of this form has previously been committed to less than n times, the form evaluates to a void? value. Otherwise, it signals a backtrack (see backtrack).

The upshot of this is that the clause containing the call to this macro can be allowed to be committed to at most n times before it always fails.

Underlyingly, each call site of this macro uses its own rule parameter (see make-rule-parameter) as a counter of how many times it’s been reached (and its clause committed to).

2.4 Sequences

jen/sequential contains forms for non-random, ordered evaluation that nonetheless depends on the current rule state.

syntax

(cycle expr ...+)

Cycles through the exprs, returning the value of one each time this form is evaluated as part of a clause. If the clause has never been committed to before, the expression will be the first one; if it has been committed to once, it will be the second one; and so on. Once all expressions have been exhausted, it begins anew with the first one.