schemeracketlogic-programmingminikanren

Why does "disj" from miniKanren work in Scheme but not in Racket?


I was working with the minikanren library for Racket, but wanted to use the "disj" and "conj" operators. I want to be able to more explicitly declare whether I am using disj or conj for the sake of legibility rather than have to parse through a conde expression, especially once the expressions become more complicated. I copied the source from "The Reasoned Schemer":

(define (append∞ s∞ t∞)
  (cond
    ((null? s∞) t∞)
    ((pair? s∞)
     (cons (car s∞)
           (append∞ (cdr s∞) t∞)))
    (else (λ ()
            (append∞ t∞ (s∞))))))

(define (disj2 g1 g2)
  (λ (s)
    (append∞ (g1 s) (g2 s))))

(define-syntax disj
  (syntax-rules ()
    [(disj) '()]
    [(disj g) g]
    [(disj g0 g ...) (disj2 g0 (disj g ...))]))

This works properly with the first two cases

> (run* (x) (disj (== 'foo x)))
'(foo)

but only returns the first result when using more than one goal:

> (run* (x) (disj (== 'foo x) (== 'bar x) (== 'foobar x)))
'(foo)

Why is this?


Solution

  • Hrmph. I can't seem to reproduce that behavior.

    When I clone the TRS/2e repo, add both

    #lang racket
    (provide (all-defined-out))
    

    to the top of trs2-impl.scm, run that file, and then try your test program I see the expected result:

    ; 
    ; Welcome to Racket v7.9.0.3 [cs].
    ; 
    trs2-impl.scm> (run* (x) (disj (== 'foo x) (== 'bar x) (== 'foobar x)))
    '((foo) (bar) (foobar))
    

    Do you see different behavior? If so, then we could look deeper. Do you know which version of Racket you're using? I don't think that will matter, but just in case.