-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcached.scm
125 lines (100 loc) · 3.25 KB
/
cached.scm
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
;;; Copyright 2016-2019 by Christian Jaeger <[email protected]>
;;; This file is free software; you can redistribute it and/or modify
;;; it under the terms of the GNU General Public License (GPL) as published
;;; by the Free Software Foundation, either version 2 of the License, or
;;; (at your option) any later version.
;; XX merge with/rename to/from memoize.scm
(require define-macro-star
;; (cj-source-util schemedefinition-arity:pattern->template)
;; is included in define-macro-star.scm
;; cj-typed -- actually
;; schemedefinition-arity:pattern->template works directly
;; with typed arguments, too!
(cj-env-2 xcase)
(vector-util let-vector)
(list-util let-pair)
(simple-match-1 assert*)
(cj-env symbol-append))
(export cached-0
cached-1
cached-2
cached-*
(macro cached-lambda)
(macro def-cached))
;; Name those cached-.., not cached/.., only use .../$n for arity of
;; the function itself (like Erlang), OK?
(define (cached-0 fn)
(let* ((t (box #f))
;; heh: can re-use t itself as nothing value!
(nothing t))
(set-box! t t)
(lambda (v)
(let ((r (unbox t)))
(if (eq? r nothing)
(let ((r (fn v)))
(table-set! t v r)
r)
r)))))
(define (cached-1 fn)
(let* ((t (make-table))
;; heh: can re-use t itself as nothing value!
(nothing t))
(lambda (v)
(let ((r (table-ref t v nothing)))
(if (eq? r nothing)
(let ((r (fn v)))
(table-set! t v r)
r)
r)))))
(define (cached-2 fn)
(let* ((t (make-table))
;; heh: can re-use t itself as nothing value!
(nothing t))
(lambda (v1 v2)
(let* ((vs (cons v1 v2))
(r (table-ref t vs nothing)))
(if (eq? r nothing)
(let ((r (fn v1 v2)))
(table-set! t vs r)
r)
r)))))
(define cached:max-arity-fixed 2)
(define (cached-* fn)
(let* ((t (make-table))
;; heh: can re-use t itself as nothing value!
(nothing t))
(lambda vs
(let ((r (table-ref t vs nothing)))
(if (eq? r nothing)
(let ((r (apply fn vs)))
(table-set! t vs r)
r)
r)))))
(define-macro* (cached-lambda binds . body)
(let-vector
((qualifier arity) (schemedefinition-arity:pattern->template
;; source-code is essential here; change ^ ?
(source-code binds)))
(define (fallback)
`(cached-* (lambda ,binds ,@body)))
(xcase qualifier
((exact)
(cond ((<= arity cached:max-arity-fixed )
`(,(symbol-append "cached-" (number->string arity))
(lambda ,binds ,@body)))
(else
(fallback))))
((at-least up-to)
(fallback)))))
;; Use 'easy' naming style but don't depend on it for definition for
;; less bootstrapping pressure (just in case I'd use it in the
;; system). Thanks to |lambda| being redefined by easy, this works with
;; typed automatically, too (assuming easy is actually loaded; anyway,
;; HACK).
(define-macro* (def-cached name+binds . body)
(assert*
pair? name+binds
(lambda (name+binds)
(let-pair
((name binds) name+binds)
`(define ,name (cached-lambda ,binds ,@body))))))