2 First Edition
| (require typed/miniKanren/amb/trs1) | package: ambKanren |
This module implements the language of the first edition of The Reasoned Schemer on top of amb.
2.1 Implementation Basis
The core follows microKanren: a goal returns one substitution and chooses among its answers with amb. There is no state and no variable counter (variables are created directly by fresh), disj and conj take any number of goals, and substitutions are immutable hash tables instead of association lists.
The user-level language provided by typed/miniKanren/amb/trs1 is that of the first edition of The Reasoned Schemer (Friedman, Byrd, and Kiselyov, MIT Press, 2005): run with a single query variable, conde with else, the interleaving forms condi and alli, and the committed-choice forms conda and condu. “Chapter n” below refers to that edition.
The differences from the book are:
There is no stream type, and ext-s performs the occurs check, signalling failure with (amb).
conde is depth-first, as in the first edition: it corresponds to unfair amb. The interleaving forms condi and alli are implemented separately (see Interleaving) after the first edition’s mplusi and bindi, and produce answers in the same order as the book.
2.2 Types
type
type
type
2.3 Running Programs
2.4 Goals
> (run* (q) (fresh (x) (== q (cons x 2)) (== x 1))) - : (Listof Term)
'((1 . 2))
> (run* (q) (== q (list q))) - : (Listof Term)
'()
syntax
(fresh (x ...) goal ...)
syntax
(project (x ...) goal ...)
> (run* (q) (fresh (n) (conde [(== n 3)] [(== n 4)]) (project (n) (if (exact-integer? n) (== q (* n n)) fail)))) - : (Listof Term)
'(9 16)
These are functions, so their arguments are evaluated before the goal is built. For recursive relations, use disj+ and conj+ or the forms below.
> (: repeato (→ Term Term Goal))
> (define (repeato x l) (conde [(== l '())] [(fresh (d) (== l (cons x d)) (repeato x d))])) > (run 6 (q) (conde [(repeato 'a q)] [(repeato 'b q)])) - : (Listof Term)
'(() (a) (a a) (a a a) (a a a a) (a a a a a))
> (run 6 (q) (condi [(repeato 'a q)] [(repeato 'b q)])) - : (Listof Term)
'(() () (a) (b) (a a) (b b))
> (run* (q) (conda [(conde [(== q 1)] [(== q 2)])] [(== q 3)])) - : (Listof Term)
'(1 2)
> (run* (q) (condu [(conde [(== q 1)] [(== q 2)])] [(== q 3)])) - : (Listof Term)
'(1)
syntax
(ife g0 g1 g2)
syntax
(ifi g0 g1 g2)
syntax
(ifa g0 g1 g2)
syntax
(ifu g0 g1 g2)
syntax
(cond-aux ifer clause ...)
syntax
(all-aux conj+ goal ...)
syntax
(if-aux disj+ g0 g1 g2)
2.4.1 Interleaving
In the example below, counto has an answer for every length, yet the answers with 'R are reached:
> (: counto (→ Term Goal))
> (define (counto n) (conde [(== n '())] [(fresh (m) (== n (cons 'I m)) (counto m))]))
> (run 6 (q) (fresh (n side) (alli (counto n) (conde [(== side 'L)] [(== side 'R)])) (== q (cons side n)))) - : (Listof Term)
'((L) (L I) (R) (L I I) (R I) (L I I I))
procedure
(mplusi s* ...) → (Sequenceof Substitution)
s* : (Sequenceof Substitution)
procedure
(bindi s* g) → (Sequenceof Substitution)
s* : (Sequenceof Substitution) g : Goal
2.5 Substitutions and Unification
value
procedure
s : Substitution
procedure
(s-has-key? x s) → Boolean
x : Var s : Substitution
procedure
s : Substitution x : Var
procedure
s : Substitution
procedure
(ext-s x v s) → Substitution
x : Var v : Term s : Substitution
procedure
v : Term s : Substitution
procedure
v : Term s : Substitution
procedure
x : Var v : Term s : Substitution
procedure
(unify u v s) → Substitution
u : Term v : Term s : Substitution
procedure
(reify-name n) → Symbol
n : Index
procedure
(reify-s v s) → Substitution
v : Term s : Substitution
procedure
v : Term
procedure
(apply-goal g s) → Substitution
g : Goal s : Substitution
procedure
(sequence->amb s) → a
s : (Sequenceof a)
procedure
(list->amb l) → a
l : (Listof a)