-
Notifications
You must be signed in to change notification settings - Fork 0
/
fixed-points.rkt
56 lines (50 loc) · 2.14 KB
/
fixed-points.rkt
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
#lang racket/base
(provide define/fix)
; Generic tools:
(define-syntax while
(syntax-rules ()
[(_ cond body ...)
; =>
(letrec ((lp (λ () (when cond body ... (lp)))))
(lp))]))
; Define a recursive (yet monotonic) function over
; a mutually recursive graph by computing its fixed
; point:
(define-syntax define/fix
(syntax-rules ()
[(_ (f x) #:bottom bottom body ...)
; =>
(define f (let ((cache (make-weak-hasheq))
(changed? (make-parameter 'error-changed))
(running? (make-parameter #f))
(visited (make-parameter 'error-visited)))
(λ (x)
(let ((cached? (hash-has-key? cache x))
(cached (hash-ref cache x (lambda () bottom)))
(run? (running?)))
(cond
[(and cached? (not run?))
; =>
cached]
[(and run? (hash-has-key? (unbox (visited)) x))
; =>
(if cached? cached bottom)]
[run?
; =>
(hash-set! (unbox (visited)) x #t)
(let ((new-val (begin body ...)))
(when (not (equal? new-val cached))
(set-box! (changed?) #t)
(hash-set! cache x new-val))
new-val)]
[(and (not cached?) (not run?))
; =>
(parameterize ([changed? (box #t)]
[running? #t]
[visited (box (make-weak-hasheq))])
(let ([v bottom])
(while (unbox (changed?))
(set-box! (changed?) #f)
(set-box! (visited) (make-weak-hasheq))
(set! v (f x)))
v))])))))]))