Brak opisu

mukanren.scm 5.2KB

    ; µKanren - http://webyrd.net/scheme-2013/papers/HemannMuKanren2013.pdf ; to use this in guile: ,import (rnrs lists) (define empty-state '(() . 0)) (define (var x) (vector x)) (define (var? x) (vector? x)) (define (var=? x y) (= (vector-ref x 0) (vector-ref y 0))) (define (walk u s) (let ((pr (and (var? u) (assp (lambda (v) (var=? u v)) s)))) (if pr (walk (cdr pr) s) u))) ; recursion b/c vars can refer to other vars? (define (ext-s x v s) `((,x . ,v) . ,s)) (define (≡ u v) (lambda (s/c) (let ((s (unify u v (car s/c)))) (if s (unit `(,s . ,(cdr s/c))) mzero)))) (define (unit s/c) (cons s/c mzero)) (define mzero '()) (define (unify u v s) (let ((u (walk u s)) (v (walk v s))) (cond ((and (var? u) (var? v) (var=? u v)) s) ((var? u) (ext-s u v s)) ((var? v) (ext-s v u s)) ((and (pair? u) (pair? v)) (let ((s (unify (car u) (car v) s))) (and s (unify (cdr u) (cdr v) s)))) (else (and (eqv? u v) s))))) (define (call/fresh f) (lambda (s/c) (let ((c (cdr s/c))) ((f (var c)) `(,(car s/c) . ,(+ c 1)))))) (define (disj g1 g2) (lambda (s/c) (mplus (g1 s/c) (g2 s/c)))) (define (conj g1 g2) (lambda (s/c) (bind (g1 s/c) g2))) ;; 4.1 finite depth first search (define (mplus $1 $2) (cond ((null? $1) $2) (else (cons (car $1) (mplus (cdr $1) $2))))) (define (bind $ g) (cond ((null? $) mzero) (else (mplus (g (car $)) (bind (cdr $) g))))) ; is this a concept or a real example? (define (fives x) (disj (≡ x 5) (fives x))) ;((call/fresh fives) empty-state) ;=> infinite loop ((call/fresh (lambda (v) (disj (≡ v 0) (≡ v 42)))) empty-state) ;; 4.2 infinite streams (define (mplus $1 $2) (cond ((null? $1) $2) ((procedure? $1) (lambda () (mplus ($1) $2))) (else (cons (car $1) (mplus (cdr $1) $2))))) (define (bind $ g) (cond ((null? $) mzero) ((procedure? $) (lambda () (bind ($) g))) (else (mplus (g (car $)) (bind (cdr $) g))))) (define (fives x) (disj (≡ x 5) (lambda (s/c) (lambda () ((fives x) s/c))))) ((call/fresh fives) empty-state) ;; 4.3 interleaved streams (define (mplus $1 $2) (cond ((null? $1) $2) ((procedure? $1) (lambda () (mplus $2 ($1)))) (else (cons (car $1) (mplus (cdr $1) $2))))) (define (sixes x) (disj (≡ x 6) (lambda (s/c) (lambda () ((sixes x) s/c))))) (define fives-and-sixes (call/fresh (lambda (x) (disj (fives x) (sixes x))))) ;; 5 utilities #| (define (expand-deferred s) (if (procedure? s) (expand-deferred (s)) s)) (define (expand-once s) (if (procedure? s) (s) s)) (define (expand n s) (if (and (> n 1) (not (null? s))) `(,(expand-deferred (car s)) . ,(expand (- n 1) (expand-once (cdr s)))) (expand-deferred s))) (expand 5 (fives-and-sixes empty-state)) (define (run n g) (expand n (g empty-state))) |# (define-syntax Zzz (syntax-rules () ((_ g) (lambda (s/c) (lambda () (g s/c)))))) (define-syntax conj+ (syntax-rules () ((_ g) (Zzz g)) ((_ g0 g ...) (conj (Zzz g0) (conj+ g ...))))) (define-syntax disj+ (syntax-rules () ((_ g) (Zzz g)) ((_ g0 g ...) (disj (Zzz g0) (disj+ g ...))))) (define-syntax conde (syntax-rules () ((_ (g0 g ...) ...) (disj+ (conj+ g0 g ...) ...)))) (define-syntax fresh (syntax-rules () ((_ () g0 g ...) (conj+ g0 g ...)) ((_ (x0 x ...) g0 g ...) (call/fresh (lambda (x0) (fresh (x ...) g0 g ...)))))) ;(run 1 (fresh (x y z) (≡ x 7) (≡ y 8) (disj (≡ x z) (≡ y z)))) ;; 5.2 from streams to lists (define (pull $) (if (procedure? $) (pull ($)) $)) (define (take-all $) (let (($ (pull $))) (if (null? $) '() (cons (car $) (take-all (cdr $)))))) (define (take n $) (if (zero? n) '() (let (($ (pull $))) (cond ((null? $) '()) (else (cons (car $) (take (- n 1) (cdr $)))))))) (take 10 ((fresh (x y z) (≡ x 7) (≡ y 8) (disj+ (≡ x z) (≡ y z) (≡ x y))) empty-state)) ;; 5.3 recovering reification (define (mK-reify s/c*) (map reify-state/1st-var s/c*)) (define (reify-state/1st-var s/c) (let ((v (walk* (var 0) (car s/c)))) (walk* v (reify-s v '())))) (define (reify-s v s) (let ((v (walk v s))) (cond ((var? v) (let ((n (reify-name (length s)))) (cons `(,v . ,n) s))) ((pair? v) (reify-s (cdr v) (reify-s (car v) s))) (else s)))) (define (reify-name n) (string->symbol (string-append "_." (number->string n)))) (define (walk* v s) (let ((v (walk v s))) (cond ((var? v) v) ((pair? v) (cons (walk* (car v) s) (walk* (cdr v) s))) (else v)))) (mK-reify (take 10 ((fresh (x y z) (≡ x 7) (≡ y 8) (disj+ (≡ x z) (≡ y z) (≡ x y))) empty-state))) (mK-reify (take 100 (fives-and-sixes empty-state))) ;; 5.4 recovering the interface to scheme (define (call/empty-state g) (g empty-state)) (define-syntax run (syntax-rules () ((_ n (x ...) g0 g ...) (mK-reify (take n (call/empty-state (fresh (x ...) g0 g ...))))))) (define-syntax run* (syntax-rules () ((_ (x ...) g0 g ...) (mK-reify (take-all (call/empty-state (fresh (x ...) g0 g ...))))))) (run 10 (y x z) (≡ x 7) (disj+ (≡ y 8) (≡ y 18) (≡ y 28)) (≡ z 9))