forked from okuoku/xitomatl
-
Notifications
You must be signed in to change notification settings - Fork 1
/
delimited-control.sls
97 lines (76 loc) · 2.88 KB
/
delimited-control.sls
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#!r6rs
;; Copyright 2009 Derick Eddington. My MIT-style license is in the file named
;; LICENSE from the original collection this file is distributed with.
;; Taken from Oleg's http://okmij.org/ftp/Scheme/delim-control-n.scm
;; NOTE: Not currently designed for multi-threaded use.
;; Won't work across phases on a multiple-instantiation system.
(library (xitomatl delimited-control)
(export
abort prompt control shift reset prompt0 control0 shift0 reset0)
(import
(rnrs))
(define cells '())
(define (cell-push! x) (set! cells (cons x cells)))
(define (cell-pop!)
(let ((x (car cells)))
(set! cells (cdr cells))
x))
(define-record-type cell (fields cont (mutable mark)))
; Essentially this is the ``return from the function''
(define (abort-top! v) ((cell-cont (cell-pop!)) v))
(define (unwind-till-marked! keep? accum)
(let ((c (if (null? cells)
(error 'unwind-till-marked! "no prompt set")
(car cells)))) ; peek at the top cell
(if (cell-mark c) ; if marked, it's prompt's cell
(begin (unless keep? (cell-mark-set! c #F))
accum)
(begin (set! cells (cdr cells)) ; remove cell from the top of stack
(unwind-till-marked! keep? (cons c accum))))))
(define (make-control shift? keep?)
(lambda (f)
(call/cc
(lambda (k-control)
(let* ((cells-prefix (unwind-till-marked! keep? '()))
(invoke-subcont (lambda (v)
(call/cc
(lambda (k-return)
(cell-push! (make-cell k-return shift?))
(for-each cell-push! cells-prefix)
(k-control v))))))
(abort-top! (f invoke-subcont)))))))
(define (prompt* thunk)
(call/cc
(lambda (outer-k)
(cell-push! (make-cell outer-k #T)) ; it's prompt's cell
(abort-top! (thunk)))))
(define control* (make-control #F #T))
(define (abort v) (control* (lambda (ignore) v)))
(define-syntax prompt
(syntax-rules ()
((_ e) (prompt* (lambda () e)))))
(define-syntax control
(syntax-rules ()
((_ k e) (control* (lambda (k) e)))))
(define-syntax reset
(syntax-rules ()
((_ e) (prompt e))))
(define shift* (make-control #T #T))
(define-syntax shift
(syntax-rules ()
((_ k e) (shift* (lambda (k) e)))))
(define-syntax prompt0
(syntax-rules ()
((_ e) (prompt e))))
(define control0* (make-control #F #F))
(define-syntax control0
(syntax-rules ()
((_ k e) (control0* (lambda (k) e)))))
(define-syntax reset0
(syntax-rules ()
((_ e) (prompt e))))
(define shift0* (make-control #T #F))
(define-syntax shift0
(syntax-rules ()
((_ k e) (shift0* (lambda (k) e)))))
)