Poole The Jekyll Butler

Running append backwards

I just watched minikanren uncourse #6 today and Will Byrd showed something absolutely incredible.

The first time I was really amazed at Prolog was from the following (standard example):

append(X,[],X). append([X|Xs],Y,[X|Zs]) :- append(Xs,Y,Zs).

it’s just the standard recursive definition of append/3, and it does append lists but it also can split the ‘output’ list into two inputs!

``` ?- append(X,Y,[a,b,c,d,e,f]).

X = [], Y = [a, b, c, d, e, f] ;

X = [a], Y = [b, c, d, e, f] ;

X = [a, b], Y = [c, d, e, f] ;

X = [a, b, c], Y = [d, e, f] ;

X = [a, b, c, d], Y = [e, f] ;

X = [a, b, c, d, e], Y = [f] ;

X = [a, b, c, d, e, f], Y = []. ```

A bit of background first. In the last uncourse hangout we saw a relational intepreter generate quines (programs whose input and output is the same): Will Byrd showed how to turn a simple little lambda calculus interpreter into a kanren relation. This time we added some operators cons, car, cdr, if to it and then…

It’s kind of impressive that the relational intepreter in minikanren can handle Y combinator based recursive functions like append:

(define (my-append-call x y) `((((lambda (f) ((lambda (x) (f (x x))) (lambda (x) (lambda (y) ((f (x x)) y))))) (lambda (my-append) (lambda (l) (lambda (s) (if (null? l) s (cons (car l) ((my-append (cdr l)) s))))))) (quote ,x)) (quote ,y)))

but what really stunned me was that minikanren is able to run the scheme append function backwards:

``` > (for-each print (run* (q) (fresh (x y) (== q (list x y)) (eval-expo (my-append-call x y) ‘() ‘(a b c d e f))))) (() (a b c d e f)) ((a) (b c d e f)) ((a b) (c d e f)) ((a b c) (d e f)) ((a b c d) (e f)) ((a b c d e) (f)) ((a b c d e f) ())

```

The code (edited a little bit to work in chicken scheme) is here.