2.21 Prolog
Complete this assignment with Team Three.
You must submit this in an archive named "prolog.zip".
You must submit this in a file named "prolog.ss".
In this assignment, you will implement Prolog-style logic variables and backtracking search using Scheme’s macros and continuations.
In this assignment, a prolog-expression? is a function that accepts a failure-continuation? and returns a success-continuation?.
A failure-continuation? is a function that accepts a value (which it ignores) and fails; failure may mean aborting the entire Prolog search (meaning it returns nothing), or it may mean backtracking to an earlier point and trying something different (meaning it returns a success-continuation?).
A success-continuation? is a function that accepts a value (which it ignores) and tries again; trying again may not be possible, so the search is aborted (meaning it returns nothing), or it may mean backtracking to an earlier point and trying something different (meaning it returns a success-continuation?).
You must define a new data structure for logic-variable?s. The assignment text imposes some constraints on this data structure. This data structure will contain prolog-value?s. prolog-value?s are numbers, strings, symbols, logic-variable?s, empty, or cons cells that only contain prolog-value?s.
You must implement the following:
(_) → logic-variable? |
(=var (v ...) e) | ||||||
|
This can be implemented by expanding to let.
(=or2 e1 e2) → prolog-expression? |
e1 : prolog-expression? |
e2 : prolog-expression? |
For example, (=or2 (=or2 =succeed =succeed) =succeed) succeeds 3 times.
(=and2 e1 e2) → prolog-expression? |
e1 : prolog-expression? |
e2 : prolog-expression? |
For example, (=and2 (=or2 =succeed =succeed) =succeed) succeeds 2 times.
(=or e ...) | ||||||
|
(=and e ...) | ||||||
|
(=find-all (v ...) e) | ||||||||||||
|
The solutions should be returned in the order of their discovery (by a left-to-right depth-first search) and each solution should list the variables in the order provided.
(=find-some n (v ...) e) | ||||||||||||||||||
|
(== e1 e2) → prolog-expression? |
e1 : prolog-value? |
e2 : prolog-value? |
If e1 and e2 can be unified, the expression succeeds. If they cannot be unified, the expression fails. Unification must always terminate: you must implement an occurs check.
2.21.1 Interactive Testing
(define resumer-box (box 'resumer)) |
(define (next) ((unbox resumer-box) 'dummy)) |
(define-syntax show |
(syntax-rules () |
[(show (vars ...) e) |
(=var (vars ...) |
(let/cc esc |
(let/cc fk |
(esc (let ([next (e fk)]) |
(set-box! resumer-box next) |
(printf "~a: ~a~n" 'vars (lv-value vars)) |
... |
(void)))) |
'fail))])) |
where lv-value accesses the value stored in the given logic variable.
Please note that these definitions are very implementation specific.
2.21.2 Testing Harness
; symbol -> boolean : returns true if and only if the given |
; symbol is an uninterned symbol |
(define (gensym? s) |
(not (equal? (string->symbol (symbol->string s)) s))) |
; list X list -> boolean : takes two bindings (for example, |
; returned from =find-all) and returns true if and only if |
; the two variables they bind are equal to the same thing. |
(define (binding-equal? b1 b2) |
(equal? (second b1) (second b2))) |
; Prolog-Expr X symbol X bool-Exprs ... -> Test result : Takes a |
; (=find-all ...) or (=find-some ...), an identifier, and a set of |
; expressions that evaluate to booleans when the identifier is |
; bound to the result of the given Prolog-expr. The test passes |
; if and only if all of the boolean expressions are true. |
(define-syntax test-prolog |
(syntax-rules (test-prolog) |
[(test-prolog find-expr result-id bool ...) |
(test (let ([result-id find-expr]) |
(and bool ...)) true)])) |
2.21.3 Additional Notes
Do not use global variables for this assignment. We expect your implementation to have the ability to do a query, capture the continuation returned, do a different query, and then invoke the first continuation with no trouble.
Unbound variables should have a unique “value” in their output. That is, if y is unbound, it should have a unique symbol as its value. If x and y are dependently unbound, they should have the same unique symbol as their values. For example, in the evaluation of (=var (x y) (== x y)), x and y are dependently unbound.
Remember that order counts. Please carefully read the definitions for =find-all and =find-some. Even if your results are correct, if they are in the wrong order or format, they will be marked as incorrect.
2.21.4 Example 1: Simple Search
(test-prolog |
(=find-all () (=or (=and =succeed =succeed) |
(=and =fail =succeed =succeed) |
(=and =succeed))) |
result |
(= (length result) 2)) |
2.21.5 Example 2: Family Trees
(define (=parent c p) |
(=or (=and (== c 'vito) (== p 'dom)) |
(=and (== c 'sonny) (== p 'vito)) |
(=and (== c 'michael) (== p 'vito)) |
(=and (== c 'fredo) (== p 'vito)) |
(=and (== c 'sophia) (== p 'michael)) |
(=and (== c 'tony) (== p 'michael)))) |
(define (=ancestor X Y) |
(=or (=parent X Y) |
(=var (Z) |
(=and (=parent X Z) |
(=ancestor Z Y))))) |
x: sonny |
x: michael |
x: fredo |
x: sophia |
x: tony |