Another Mirco Kanren- embed logic programming into Scheme. Run the given AMK query and return its result, if any. See the book Logic Progamming in Scheme for an introduction to AMK.
| symbol | variable binding the result (optional) |
|---|---|
| query | AMK program |
(run* (vq) (appendo vq (_) '(a b c))) => (() (a) (a b) (a b c))
; ----- core -----
(define (fail x) '())
(define (succeed x) (list x))
(define failed? null?)
(define (var x) (cons '? x))
(define (var? x)
(and (pair? x)
(eq? (car x) '?)))
(define empty-s '())
(define _bottom_ (var 'bottom))
(define (atom? x) (not (pair? x)))
(define (ext-s x v s) (cons (cons x v) s))
(define (walk x s)
(if (not (var? x))
x
(let ((v (assq x s)))
(if v
(walk (cdr v) s)
x))))
(define (unify x y s)
(let ((x (walk x s))
(y (walk y s)))
(cond
((eqv? x y) s)
((var? x) (ext-s x y s))
((var? y) (ext-s y x s))
((or (atom? x) (atom? y)) #f)
(else (let ((s (unify (car x) (car y) s)))
(and s (unify (cdr x) (cdr y) s)))))))
(define (== x y)
(lambda (s)
(let ((s2 (unify x y s)))
(if s2
(succeed s2)
(fail s)))))
(define (any* . g*)
(lambda (s)
(letrec
((try
(lambda g*
(if (null? g*)
(fail s)
(append ((car g*) s)
(apply try (cdr g*)))))))
(apply try g*))))
(define-syntax any
(syntax-rules ()
((_) fail)
((_ g ...)
(any* (lambda (s) (g s)) ...))))
(define (all . gs)
(lambda (s)
(letrec
((try
(lambda (gs subs)
(if (null? gs)
subs
(try (cdr gs)
(apply append
(map (car gs) subs)))))))
(try gs (succeed s)))))
(define (one* . gs)
(lambda (s)
(letrec
((try
(lambda gs
(if (null? gs)
(fail s)
(let ((out ((car gs) s)))
(if (failed? out)
(apply try (cdr gs))
out))))))
(apply try gs))))
(define-syntax one
(syntax-rules ()
((_) fail)
((_ g ...)
(one* (lambda (s) (g s)) ...))))
(define (neg g)
(lambda (s)
(let ((out (g s)))
(if (failed? out)
(succeed s)
(fail s)))))
(define-syntax fresh
(syntax-rules ()
((_ () g)
(let () g))
((_ (v ...) g)
(let ((v (var 'v)) ...) g))))
(define (occurs? x y s)
(let ((v (walk y s)))
(cond
((var? y) (eq? x y))
((var? v) (eq? x v))
((atom? v) #f)
(else (or (occurs? x (car v) s)
(occurs? x (cdr v) s))))))
(define (circular? x s)
(let ((v (walk x s)))
(if (eq? x v)
#f
(occurs? x (walk x s) s))))
(define (walk* x s)
(letrec
((w*
(lambda (x s)
(let ((x (walk x s)))
(cond
((var? x) x)
((atom? x) x)
(else (cons (w* (car x) s)
(w* (cdr x) s))))))))
(cond
((circular? x s) _bottom_)
((eq? x (walk x s)) empty-s)
(else (w* x s)))))
(define (preserve-bottom s)
(if (occurs? _bottom_ s s)
'()
s))
(define (reify-name n)
(string->symbol
(string-append "_." (number->string n))))
(define (reify v)
(letrec
((reify-s
(lambda (v s)
(let ((v (walk v s)))
(cond
((var? v)
(ext-s v (reify-name (length s)) s))
((atom? v) s)
(else (reify-s (cdr v)
(reify-s (car v) s))))))))
(reify-s v empty-s)))
(define (_) (var '_))
(define (run x g)
(preserve-bottom
(map (lambda (s)
(walk* x (append s (reify (walk* x s)))))
(g empty-s))))
(define-syntax run*
(syntax-rules ()
((_ () goal) (run #f goal))
((_ (v) goal) (run v goal))))
; ----- tools -----
(define vp (var 'p))
(define vq (var 'q))
(define vr (var 'r))
(define (conso a d p) (== (cons a d) p))
(define (caro p a) (conso a (_) p))
(define (cdro p d) (conso (_) d p))
(define (pairo p) (conso (_) (_) p))
(define (eqo x y) (== x y))
(define (nullo a) (eqo a '()))
(define (memo x l)
(fresh (a d)
(any (all (caro l a)
(eqo x a))
(all (cdro l d)
(memo x d)))))
(define (appendo x y r)
(any (all (== x '())
(== y r))
(fresh (vh vt va)
(all (conso vh vt x)
(conso vh va r)
(appendo vt y va)))))
(define (membero x l r)
(fresh (a d)
(any (all (caro l a)
(eqo x a)
(== r l))
(all (cdro l d)
(membero x d r)))))