Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ failing arm of the result rather than as a throw; `ok` tells the two apart.
- [Basic usage](#basic-usage): a rule compiled once and evaluated against two loans.
- [Compiling a rule](#compiling-a-rule): a rule compiled, run and refused, with each result checked.
- Do
- [How to compile and evaluate a rule](https://github.com/riddler/predicator-ts/blob/main/docs/guides/how-to-compile-and-evaluate-a-rule.md): compile a rule's text, keep the instruction list, and decide the rule for one loan.
- [Rendering a rule back](#rendering-a-rule-back): show an authored rule back to its author in a normalized form.
- [Statement programs](#statement-programs): run a short script that assigns into its context.
- [Writing a location](#writing-a-location): write an assignment's location into your own data without running a program.
Expand Down
96 changes: 96 additions & 0 deletions docs/guides/how-to-compile-and-evaluate-a-rule.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# How to compile and evaluate a rule

This guide shows you how to turn a rule a librarian writes into an instruction
list, keep that list, and decide the rule for one loan.

You start with `@riddler/predicator` installed and the rule as text: here, a
copy counts as lost when its loan is more than thirty days overdue and the copy
is still checked out.

## Compile the rule

1. Import `compile` and pass it the rule's text.

```ts
import { compile } from "@riddler/predicator";

const compiled = compile("loan.days_overdue > 30 AND copy.status == 'checked_out'");
```

`compiled.ok` is `true`.

2. Check `ok` before you use the result.

```ts
if (!compiled.ok) {
throw new Error(compiled.error.message);
}
```

After the check, `compiled.instructions` is the instruction list, starting
`["load", "loan"], ["access", "days_overdue"], ["lit", 30]`.

3. If the rule does not compile, show the author where it failed. For
`compile("loan.days_overdue > ")`, `compiled.ok` is `false`,
`compiled.error.reason` is `"expected_primary"` and
`compiled.error.position` is `{ line: 1, column: 21 }`, the place the text
ran out.

## Keep the instruction list

1. Store or send the list as JSON.

```ts
const stored = JSON.stringify(compiled.instructions);
```

`stored` is a JSON array of arrays that starts `[["load","loan"],`.

2. Read it back where the rule is decided.

```ts
const instructions = JSON.parse(stored);
```

`instructions` holds the same list `compile` answered.

If the rule carries a date, a datetime or a float, plain JSON does not keep it:
store the `text` that `encodeTagged(compiled.instructions)` answers instead,
and read it back with `decodeTagged`, both from `@riddler/predicator/tagged`
([the tagged subpath](https://github.com/riddler/predicator-ts/blob/main/README.md#the-tagged-subpath)).

## Evaluate the rule for a loan

1. Import `evaluate` and pass it the instruction list and a context that binds
every name the rule reads.

```ts
import { evaluate } from "@riddler/predicator";

const decision = evaluate(instructions, {
loan: { days_overdue: 45 },
copy: { status: "checked_out" },
});
```

`decision` is `{ ok: true, value: true }`: this copy counts as lost.

2. Evaluate it again for a copy that has come back.

```ts
const returned = evaluate(instructions, {
loan: { days_overdue: 45 },
copy: { status: "returned" },
});
```

`returned` is `{ ok: true, value: false }`.

3. Check `ok` before you read `value`. For a context that leaves `loan` out,
`ok` is `false`, `error.type` is `"UndefinedVariableError"` and
`error.reason` is `"unbound_variable"`.

For what a failed evaluation carries and the options `evaluate` takes, see
[Evaluating a rule](https://github.com/riddler/predicator-ts/blob/main/README.md#evaluating-a-rule)
and
[Evaluation options](https://github.com/riddler/predicator-ts/blob/main/README.md#evaluation-options).
Loading