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ñé?
"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
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. –
La lista diferida también es posible en el esquema, vale, no es la predeterminada. – knivil