Search code examples
logicschemeracketeval

Why does AND, OR work as expected but an error is shown with XOR?


(define-syntax e.g.
  (syntax-rules (===>)
    ((e.g. proposition)
     (unless proposition
       (error "invalid proposition: "'proposition)))
    ((e.g. proposition ===> value)
     (let ((result proposition))
       (unless (equal? proposition value)
         (error "invalid proposition: "'proposition
                ", expected "value", got "result))))))

(define my-eval
  (let ((ns (make-base-namespace)))
    (lambda (expr) (eval expr ns))))

(e.g. (my-eval '(and #t #t)) ===> #t)
(e.g. (my-eval '(and #t #f)) ===> #f)
(e.g. (my-eval '(or #t #f)) ===> #t)
(e.g. (my-eval '(or #f #f)) ===> #f)
(e.g. (my-eval '(xor #t #t)) ===> #f)
(e.g. (my-eval '(xor #t #f)) ===> #t)

It works correctly for AND,OR but for XOR:

XOR: undefined; cannot reference an identifier before its definition.

even tough in the REPL seems to work correctly:

(xor #t #f)

t


Solution

  • The question is who has time to read whole documents like that?

    You don't have to read it all in one sitting, but that is where the information is, and Racket has a lot of great documentation.

    eval can be a bit slippery in Racket; you need to finish setting up the namespace where the eval expression is evaluated. One way to do this is to use parameterize to create an empty namespace. This needs to happen inside the lambda expression, i.e., the environment in which eval is evaluated, and you need to be sure that both racket/base and racket/bool are required:

    #lang racket
    
    (define-syntax e.g.
      (syntax-rules (===>)
        ((e.g. proposition)
         (unless proposition
           (error "invalid proposition: " 'proposition)))
        ((e.g. proposition ===> value)
         (let ((result proposition))
           (unless (equal? proposition value)
             (error "invalid proposition: " 'proposition
                    ", expected " value ", got " result))))))
    
    (define my-eval
      (lambda (expr)
        (parameterize ([current-namespace (make-base-empty-namespace)])
          (namespace-require 'racket/base)
          (namespace-require 'racket/bool)
          (eval expr))))
    
    (e.g. (my-eval '(and #t #t)) ===> #t)
    (e.g. (my-eval '(and #t #f)) ===> #f)
    (e.g. (my-eval '(or #t #f)) ===> #t)
    (e.g. (my-eval '(or #f #f)) ===> #f)
    (e.g. (my-eval '(xor #t #t)) ===> #f)
    (e.g. (my-eval '(xor #t #f)) ===> #t)