2011-04-24 8 views
5

En this página hay un comentario después de que el mensaje que le da un muy corto implementación de amb como procedimiento:`amb` operador como macro o procedimiento?

(define (amb-backtrack) 
    (error "no solution found")) 

(define (amb . args) 
    (call/cc (lambda (return) 
      (let ((backtrack amb-backtrack)) 
       (map (lambda (x) 
         (call/cc (lambda (k) 
           (set! amb-backtrack k) 
           (return x)))) 
        args) 
       (backtrack 'fail))))) 

Pero yo suelo ver amb implementado como una macro - en el FAQ schemers.org, y también en Dorai Sitaram's book:

(define amb-fail '*) 

(define initialize-amb-fail 
    (lambda() 
    (set! amb-fail 
     (lambda() 
     (error "amb tree exhausted"))))) 

(initialize-amb-fail) 

(define-macro amb 
    (lambda alts... 
    `(let ((+prev-amb-fail amb-fail)) 
     (call/cc 
     (lambda (+sk) 

      ,@(map (lambda (alt) 
        `(call/cc 
        (lambda (+fk) 
         (set! amb-fail 
         (lambda() 
          (set! amb-fail +prev-amb-fail) 
          (+fk 'fail))) 
         (+sk ,alt)))) 
       alts...) 

      (+prev-amb-fail)))))) 

por lo tanto - la versión macro es más largo, y un poco más difícil de entender. No pude ver ninguna ventaja sobre la versión del procedimiento, y por supuesto prefiero usar un procedimiento que una macro. ¿Hay algo que extrañé?

Respuesta

6

La diferencia es que una llamada de procedimiento siempre evalúa todos los argumentos.

(amb 1 (very-expensive-computation)) 

será, con la versión de procedimiento de amb, realice el very-expensive-computation, a continuación, producir 1. Si rendir 1 es suficiente para todos los cálculos posteriores, habrá perdido mucho tiempo en un cálculo cuyo valor de resultado nunca se utiliza. Incluso cosas peores ocurren, como menciona @Eli Barzilay en un comentario, cuando amb se usa para modelar un no determinismo infinito, como generar todos los números naturales.

La versión de macro lo evita y, por lo tanto, su comportamiento es similar al de los lenguajes de programación no deterministas, como Prolog.

+0

"y su comportamiento es por lo tanto más cercano al de lenguajes de programación no deterministas como Prolog" -> ¡Gracias! Sabía que el procedimiento evaluaría todos los argumentos, pero no pensé en la similitud de la versión de macro con programación no determinista en general. – Jay

+3

Es mucho más que perder el tiempo: considere una función con un segundo subformulario 'amb' que llama a la función en un ciclo infinito. (Eso ni siquiera es algo académico sin uso: sería una forma natural de implementar un 'amb' para todos los enteros). Tal cosa sería imposible si' amb' es una función simple. –

+1

La lista diferida también es posible en el esquema, vale, no es la predeterminada. – knivil