either.scm 2.0 KB

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