method.scm 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. ; Authors: Richard Kelsey, Jonathan Rees, Mike Sperber
  3. ; Generic procedure package
  4. ; This is written in fairly portable Scheme. It needs:
  5. ; Scheme 48 low-level macros (explicit renaming), in one small place.
  6. ; (ASSERTION-VIOLATION who message arg ...) - signal an error.
  7. ; Record package and DEFINE-RECORD-TYPES macro.
  8. ; An object :RECORD-TYPE which is the record type descriptor for
  9. ; record type descriptors (record types are assumed to be records).
  10. ; This wouldn't be difficult to change.
  11. ; A RECORD? predicate (not essential - only for defining a DISCLOSE
  12. ; method for records).
  13. ; --------------------
  14. ; Simple types.
  15. ; More specific types have higher priorities. The priorities are used
  16. ; to establish the ordinary in which type predicates are called.
  17. (define-record-type simple-type :simple-type
  18. (really-make-simple-type supers predicate priority id)
  19. simple-type?
  20. (supers simple-type-superiors)
  21. (predicate simple-type-predicate)
  22. (priority simple-type-priority)
  23. (id simple-type-id)
  24. (more)) ;if needed later
  25. (define-record-discloser :simple-type
  26. (lambda (c) `(simple-type ,(simple-type-id c))))
  27. (define (make-simple-type supers predicate id)
  28. (make-immutable!
  29. (really-make-simple-type supers
  30. predicate
  31. (compute-priority supers)
  32. id)))
  33. (define (compute-priority supers)
  34. (if (null? supers)
  35. 0
  36. (+ (apply max (map %type-priority supers))
  37. *increment*)))
  38. (define *increment* 10)
  39. ; These two procedures will become generic later, but must exist early
  40. ; in order to be able to bootstrap the method definition mechanism.
  41. (define (%type-priority type)
  42. (cond ((simple-type? type)
  43. (simple-type-priority type))
  44. ((record-type? type)
  45. (record-type-priority type))
  46. (else (type-priority type)))) ;generic
  47. (define (%type-predicate type)
  48. (cond ((simple-type? type)
  49. (simple-type-predicate type))
  50. ((record-type? type)
  51. (record-predicate type))
  52. (else (type-predicate type)))) ;generic
  53. (define (%same-type? t1 t2)
  54. (or (eq? t1 t2)
  55. (if (simple-type? t1)
  56. #f
  57. (if (record-type? t1)
  58. #f
  59. (same-type? t1 t2)))))
  60. (define-syntax define-simple-type
  61. (syntax-rules ()
  62. ((define-simple-type ?name (?super ...) ?pred)
  63. (define ?name (make-simple-type (list ?super ...) ?pred '?name)))))
  64. ; --------------------
  65. ; Built-in Scheme types
  66. ; We don't call them :<type> because some of these would conflict with
  67. ; the types from the `types' structure.
  68. (define-simple-type <syntax> () #f)
  69. (define-simple-type <values> () #f) ;any number of values
  70. (define (value? x) #t)
  71. (define-simple-type <value> (<values>) value?)
  72. (define-simple-type <zero> (<values>) (lambda (x) #f))
  73. (define-simple-type <number> (<value>) number?)
  74. (define-simple-type <complex> (<number>) complex?)
  75. (define-simple-type <real> (<complex>) real?)
  76. (define-simple-type <rational> (<real>) rational?)
  77. (define-simple-type <integer> (<rational>) integer?)
  78. (define-simple-type <exact-integer> (<integer>)
  79. (lambda (n) (and (integer? n) (exact? n))))
  80. (define-simple-type <boolean> (<value>) boolean?)
  81. (define-simple-type <symbol> (<value>) symbol?)
  82. (define-simple-type <char> (<value>) char?)
  83. (define-simple-type <null> (<value>) null?)
  84. (define-simple-type <pair> (<value>) pair?)
  85. (define-simple-type <vector> (<value>) vector?)
  86. (define-simple-type <string> (<value>) string?)
  87. (define-simple-type <procedure> (<value>) procedure?)
  88. (define-simple-type <input-port> (<value>) input-port?)
  89. (define-simple-type <output-port> (<value>) output-port?)
  90. (define-simple-type <eof-object> (<value>) eof-object?)
  91. ; If there is no RECORD? predicate, do
  92. ; (define-simple-type <record> (<value>) value?)
  93. ; and change the DISCLOSE method for records to
  94. ; (or (disclose-record obj) (next-method)).
  95. (define-simple-type <record> (<value>) record?)
  96. ; If record types are not records, un-comment the following line.
  97. ; (define-simple-type :record-type (<value>) record-type?)
  98. ; Given a record type, RECORD-TYPE-PRIORITY returns its priority.
  99. ; Here we establish that every record type is a direct subtype of the
  100. ; <RECORD> type.
  101. (define record-type-priority
  102. (let ((r-priority
  103. (simple-type-priority (make-simple-type (list <record>) #f #f))))
  104. (lambda (rt) r-priority)))
  105. ; --------------------
  106. ; Method-info records are triples <type-list, n-ary?, proc>.
  107. (define-record-type method-info :method-info
  108. (really-make-method-info types n-ary? proc)
  109. method-info?
  110. (types method-info-types)
  111. (n-ary? method-info-n-ary?)
  112. (proc method-info-proc))
  113. (define (make-method-info types n-ary? proc)
  114. (make-immutable! (really-make-method-info types n-ary? proc)))
  115. (define-record-discloser :method-info
  116. (lambda (info)
  117. `(method-info ,(method-info-types info) ,(method-info-n-ary? info))))
  118. ; --------------------
  119. ; Method lists
  120. ; A method list is a list of method-info records, sorted in order from
  121. ; most specific to least specific.
  122. (define (empty-method-list) '())
  123. ; insert-method inserts an entry into a method list so that the most
  124. ; specific methods come earliest in the list. The last method should
  125. ; be a default method or error signal(l)er.
  126. (define (insert-method info ms)
  127. (let recur ((ms ms))
  128. (if (null? ms)
  129. (cons info ms)
  130. (if (more-specific? (car ms) info)
  131. (cons (car ms) (recur (cdr ms)))
  132. (cons info
  133. (if (same-applicability? (car ms) info)
  134. (cdr ms)
  135. ms))))))
  136. ; Replace an existing method with identical domain.
  137. (define (same-applicability? info1 info2)
  138. (and (every2 %same-type?
  139. (method-info-types info1)
  140. (method-info-types info2))
  141. (eq? (method-info-n-ary? info1) (method-info-n-ary? info2))))
  142. (define (every2 pred l1 l2)
  143. (if (null? l1)
  144. (null? l2)
  145. (if (null? l2)
  146. #f
  147. (and (pred (car l1) (car l2)) (every2 pred (cdr l1) (cdr l2))))))
  148. ; This interacts with methods->perform, below.
  149. ; In this version, it's supposed to be a total order.
  150. (define (more-specific? info1 info2)
  151. (let ((t1 (method-info-types info1))
  152. (t2 (method-info-types info2)))
  153. (let ((l1 (length t1))
  154. (l2 (length t2))
  155. (foo? (and (not (method-info-n-ary? info1))
  156. (method-info-n-ary? info2))))
  157. (if (= l1 l2)
  158. (or foo?
  159. (let loop ((l1 t1)
  160. (l2 t2))
  161. (if (null? l2)
  162. #f
  163. (or (more-specific-type? (car l1) (car l2))
  164. (and (%same-type? (car l1) (car l2))
  165. (loop (cdr l1) (cdr l2)))))))
  166. (and (> l1 l2)
  167. foo?)))))
  168. (define (more-specific-type? t1 t2)
  169. (> (%type-priority t1) (%type-priority t2)))
  170. ; --------------------
  171. ; A method table is a cell that contains a method list.
  172. ; Note that the method table is not reachable from the generic
  173. ; procedure. This means good things for the GC.
  174. (define-record-type method-table :method-table
  175. (really-make-method-table methods prototype
  176. generic get-perform set-perform! id)
  177. method-table?
  178. (methods method-table-methods set-method-table-methods!)
  179. (prototype method-table-prototype)
  180. (generic make-generic)
  181. (get-perform method-table-get-perform)
  182. (set-perform! method-table-set-perform!)
  183. (id method-table-id))
  184. (define-record-discloser :method-table
  185. (lambda (t) `(method-table ,(method-table-id t))))
  186. (define (make-method-table id . option)
  187. (let* ((prototype (if (null? option)
  188. (make-method-info '() #t #f)
  189. (car option)))
  190. (mtable (call-with-values make-cell-for-generic
  191. (lambda (generic get-perform set-perform!)
  192. (really-make-method-table '()
  193. prototype
  194. generic
  195. get-perform
  196. set-perform!
  197. id)))))
  198. (set-final-method!
  199. mtable
  200. (lambda (next-method . args)
  201. (apply assertion-violation '<method> "invalid or unimplemented operation"
  202. id args)))
  203. mtable))
  204. (define (make-cell-for-generic)
  205. (let ((perform #f))
  206. ;; PERFORM always caches (METHODS->PERFORM method-list prototype).
  207. (values (lambda args (perform args)) ;Generic proc
  208. (lambda () perform)
  209. (lambda (new) (set! perform new)))))
  210. (define (add-to-method-table! mtable info)
  211. (let ((l (insert-method info (method-table-methods mtable))))
  212. (set-method-table-methods! mtable l)
  213. ((method-table-set-perform! mtable)
  214. (methods->perform l (method-table-prototype mtable)))))
  215. (define (set-final-method! mtable proc)
  216. (add-to-method-table! mtable
  217. (make-method-info '()
  218. #t
  219. proc)))
  220. (define (apply-generic mtable args)
  221. ;; (apply (make-generic mtable) args)
  222. (((method-table-get-perform mtable)) args)) ;+++
  223. ; DEFINE-GENERIC
  224. (define-syntax define-generic
  225. (syntax-rules ()
  226. ((define-generic ?name ?mtable-name)
  227. (begin (define ?mtable-name (make-method-table '?name))
  228. (define ?name (make-generic ?mtable-name))))
  229. ((define-generic ?name ?mtable-name (?spec . ?specs))
  230. (begin (define ?mtable-name
  231. (make-method-table '?name
  232. (method-info ?name ("next" next-method
  233. ?spec . ?specs)
  234. (next-method))))
  235. (define ?name (make-generic ?mtable-name))))))
  236. ; --------------------
  237. ; Method combination.
  238. ; Here is the specification:
  239. ;(define (apply-generic mtable args)
  240. ; (let loop ((ms (method-table-methods mtable)))
  241. ; (let ((next-method (lambda () (loop (cdr ms)))))
  242. ; (if (let test ((ts (method-info-types (car ms)))
  243. ; (args args))
  244. ; (if (null? ts)
  245. ; (or (null? args)
  246. ; (method-info-n-ary? (car ms)))
  247. ; (and ((%type-predicate (car ts)) (car args))
  248. ; (test (cdr ts) (cdr args)))))
  249. ; (apply (method-info-proc (car ms))
  250. ; next-method
  251. ; args)
  252. ; (next-method)))))
  253. ; (perform arg-list)
  254. ; (apply proc next-method-thunk arg-list)
  255. ; This version of METHODS->PERFORM simply marches through all the
  256. ; methods, looking for one that handles the operation.
  257. ; The prototype is currently ignored, but it could be put to good use.
  258. (define (methods->perform l prototype)
  259. (let recur ((l l))
  260. (let* ((info (car l))
  261. (proc (method-info-proc info)))
  262. (if (null? (cdr l))
  263. (last-action proc)
  264. (one-action (argument-sequence-predicate info)
  265. proc
  266. (recur (cdr l)))))))
  267. (define (last-action proc)
  268. (lambda (args)
  269. (apply proc #f args)))
  270. (define (one-action pred proc perform-next)
  271. (lambda (args)
  272. (if (pred args)
  273. (apply proc
  274. (lambda () (perform-next args)) ; next-method
  275. args)
  276. (perform-next args))))
  277. (define (argument-sequence-predicate info)
  278. (let recur ((types (method-info-types info)))
  279. (if (null? types)
  280. (if (method-info-n-ary? info) value? null?)
  281. (let ((pred (%type-predicate (car types)))
  282. (check-rest (recur (cdr types))))
  283. (if (eq? pred value?)
  284. (check-for-next check-rest) ;+++
  285. (check-next pred check-rest))))))
  286. (define (check-for-next check-rest)
  287. (lambda (args)
  288. (if (null? args)
  289. #f
  290. (check-rest (cdr args)))))
  291. (define (check-next pred check-rest)
  292. (lambda (args)
  293. (if (null? args)
  294. #f
  295. (if (pred (car args))
  296. (check-rest (cdr args))
  297. #f))))
  298. ; --------------------
  299. ; METHOD-INFO macro.
  300. ; Returns a method-info record.
  301. ; You can specify the name of the next-method parameter by saying
  302. ; (method-info my-name (x y "next" n) body ...)
  303. ; Otherwise, the next-method parameter will be named next-method.
  304. ; Just pretend it's Dylan and that #next reads as "next".
  305. (define-syntax method-info
  306. (syntax-rules ()
  307. ((method-info ?id ?formals ?body ...)
  308. (method-internal ?formals () () #f ?id ?body ...))))
  309. (define-syntax method-internal
  310. (syntax-rules ()
  311. ((method-internal ((?formal1 ?type1) . ?specs)
  312. (?formal ...) (?type ...) ?next
  313. . ?rest)
  314. (method-internal ?specs
  315. (?formal ... ?formal1) (?type ... ?type1) ?next
  316. . ?rest))
  317. ((method-internal ("next" ?next . ?specs)
  318. (?formal ...) (?type ...) ?ignore
  319. . ?rest)
  320. (method-internal ?specs
  321. (?formal ...) (?type ...) ?next
  322. . ?rest))
  323. ((method-internal (?spec . ?specs)
  324. (?formal ...) (?type ...) ?next
  325. . ?rest)
  326. (method-internal ?specs
  327. (?formal ... ?spec) (?type ... <value>) ?next
  328. . ?rest))
  329. ((method-internal ?rest
  330. (?formal ...) (?type ...) ?next
  331. ?id ?body ...)
  332. (make-method-info (list ?type ...)
  333. (not (null? '?rest))
  334. (let ((?id (with-next-method ?next (?formal ... . ?rest)
  335. ?body ...)))
  336. ;; The (let ...) is a hack for the Scheme 48
  337. ;; byte code compiler, which will remember
  338. ;; ?id as the procedure's name. This should
  339. ;; aid debugging a little bit since the name
  340. ;; shows up in backtraces and the inspector.
  341. ?id)))))
  342. ; Non-hygienic, a la Dylan
  343. (define-syntax with-next-method
  344. (cons (lambda (e r c)
  345. (let ((next (or (cadr e) 'next-method)))
  346. `(,(r 'lambda) (,next ,@(caddr e))
  347. ,@(cdddr e))))
  348. '(lambda)))
  349. ; DEFINE-METHOD macro.
  350. (define-syntax define-method
  351. (syntax-rules ()
  352. ((define-method ?mtable ?formals ?body ...)
  353. (add-method! ?mtable
  354. (method-info ?mtable ?formals ?body ...)))))
  355. (define-generic add-method! &add-method! (mtable info))
  356. (let ((info
  357. (method-info add-method! ((mtable :method-table) (info :method-info))
  358. (add-to-method-table! mtable info))))
  359. (add-to-method-table! &add-method! info))
  360. ; --------------------
  361. ; Generic functions on types: sort of a meta-object protocol, huh?
  362. (define-generic type-predicate &type-predicate (t))
  363. (define-method &type-predicate ((t :record-type)) (record-predicate t))
  364. (define-method &type-predicate ((t :simple-type)) (simple-type-predicate t))
  365. (define-generic type-priority &type-priority (t))
  366. (define-method &type-priority ((t :record-type)) (record-type-priority t))
  367. (define-method &type-priority ((t :simple-type)) (simple-type-priority t))
  368. (define-generic type-superiors &type-superiors (t))
  369. (define-method &type-superiors ((t :record-type)) (list <record>))
  370. (define-method &type-superiors ((t :simple-type)) (simple-type-superiors t))
  371. ; Type equivalence
  372. (define-generic same-type? &same-type? (t1 t2))
  373. (define-method &same-type? (t1 t2) (eq? t1 t2))
  374. (define-method &same-type? ((t1 :simple-type) (t2 :simple-type))
  375. (and (eq? (simple-type-predicate t1) (simple-type-predicate t2))
  376. (eq? (simple-type-id t1) (simple-type-id t2)))) ;?
  377. ; --------------------
  378. ; Singleton types.
  379. (define-record-type singleton :singleton
  380. (singleton value)
  381. (value singleton-value))
  382. (define-record-discloser :singleton
  383. (lambda (s) `(singleton ,(singleton-value s))))
  384. (define (compare-to val)
  385. (lambda (x) (eqv? x val)))
  386. (define-method &type-predicate ((s :singleton))
  387. (compare-to (singleton-value s)))
  388. (define-method &type-priority ((s :singleton)) 1000000)
  389. (define-method &same-type? ((s1 :singleton) (s2 :singleton))
  390. (eqv? (singleton-value s1) (singleton-value s2)))
  391. ; --------------------
  392. ; DISCLOSE
  393. ; A generic procedure for producing printed representations.
  394. ; Should return one of
  395. ; - A list (symbol info ...), to be printed as #{Symbol info ...}
  396. ; - #f, meaning no information available on how to print.
  397. ; This is intended to be used not only by write and display, but also by
  398. ; the pretty printer.
  399. (define-generic disclose &disclose (x))
  400. (define-method &disclose (obj) #f)
  401. (define-method &disclose ((obj <record>))
  402. (or (disclose-record obj)
  403. '(record)))
  404. (define-method &add-method! ((d (singleton &disclose)) info)
  405. (let ((t (car (method-info-types info))))
  406. (if (record-type? t)
  407. (define-record-discloser t (proc->discloser (method-info-proc info)))
  408. (next-method))))
  409. (define (proc->discloser proc)
  410. (lambda (arg)
  411. (proc (lambda () #f) arg)))
  412. ;(define-method &disclose ((s :singleton))
  413. ; `(singleton ,(singleton-value s)))