either.scm 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. ; Authors: Richard Kelsey, Jonathan Rees, Mike Sperber
  3. ; Nondeterminism, Prolog, or whatever you want to call it. This is
  4. ; depth-first search implemented using call/cc.
  5. ; The fluid variable $FAIL is bound to a thunk to be called in case of failure.
  6. (define $fail
  7. (make-fluid (make-cell
  8. (lambda ()
  9. (assertion-violation 'fail
  10. "call to FAIL outside WITH-NONDETERMINISM")))))
  11. (define (with-nondeterminism thunk)
  12. (let-fluid $fail
  13. (make-cell (lambda ()
  14. (assertion-violation 'with-nondeterminism
  15. "nondeterminism ran out of choices")))
  16. thunk))
  17. ; Call the current failure function.
  18. (define (fail)
  19. ((fluid-cell-ref $fail)))
  20. ; For the alternation operator, Icon's a | b or McCarthy's (amb a b),
  21. ; we write (either a b).
  22. (define-syntax either
  23. (syntax-rules ()
  24. ((either) (fail))
  25. ((either x) x)
  26. ((either x y ...)
  27. (%either (lambda () x) (lambda () (either y ...))))))
  28. ; 1. Save the current failure procedure and continuation.
  29. ; 2. Install a new failure procedure that restores the old failure procedure
  30. ; and continuation and then calls THUNK2.
  31. ; 3. Call THUNK1.
  32. (define (%either thunk1 thunk2)
  33. (let ((save (fluid-cell-ref $fail)))
  34. ((call-with-current-continuation
  35. (lambda (k)
  36. (fluid-cell-set! $fail
  37. (lambda ()
  38. (fluid-cell-set! $fail save)
  39. (k thunk2)))
  40. thunk1)))))
  41. ; (one-value x) is Prolog's CUT operator. X is allowed to return only once.
  42. (define-syntax one-value
  43. (syntax-rules ()
  44. ((one-value x) (%one-value (lambda () x)))))
  45. (define (%one-value thunk)
  46. (let ((save (fluid-cell-ref $fail)))
  47. (call-with-values thunk
  48. (lambda args
  49. (fluid-cell-set! $fail save)
  50. (apply values args)))))
  51. ; (all-values a) returns a list of all the possible values of the
  52. ; expression a. Prolog calls this "bagof"; I forget what Icon calls it.
  53. (define-syntax all-values
  54. (syntax-rules ()
  55. ((all-values x) (%all-values (lambda () x)))))
  56. (define (%all-values thunk)
  57. (let ((results '()))
  58. (either (let ((new-result (thunk)))
  59. (set! results (cons new-result results))
  60. (fail))
  61. (reverse results))))