finite-type.scm 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. ; Authors: Richard Kelsey, Jonathan Rees
  3. ; Finite types (i.e. record types with a fixed set of elements).
  4. ;
  5. ; An enumeration is really a special case of a finite type.
  6. ;
  7. ; (define-finite-type <id and dispatch-macro>
  8. ; <type name>
  9. ; (<constructor field name> ...)
  10. ; <predicate>
  11. ; <vector of elements>
  12. ; <name accessor>
  13. ; <index accessor>
  14. ; (<field name> <field accessor> [<field setter>])
  15. ; ...
  16. ; ((<element name> <constructor field value> ...)
  17. ; ...))
  18. ;
  19. ; This is equivalent to
  20. ;
  21. ; (define-record-type <id and dispatch-macro>
  22. ; <type name>
  23. ; (maker name index <constructor field name> ...)
  24. ; <predicate>
  25. ; (name <name accessor>)
  26. ; (index <index accessor>)
  27. ; (<field name> <field accessor> [<field setter>])
  28. ; ...)
  29. ;
  30. ; (define <vector of elements>
  31. ; (vector (maker <element name> 0 <constructor field value>)
  32. ; (maker <element name> 1 <constructor field value>)
  33. ; ...))
  34. ;
  35. ; (define-dispatch-macro <id and dispatch-macro>
  36. ; (<element name> ...)
  37. ; <vector-of-elements>)
  38. ;
  39. ; where DEFINE-DISPATCH-MACRO defines an ENUM-like dispatcher.
  40. ;
  41. ;(define-finite-type foo :foo ; id and type
  42. ; foo? ; predicate
  43. ; foo-elements ; vector containing all elements
  44. ; foo-name ; name accessor
  45. ; foo-index ; index accessor
  46. ; (color foo-color set-foo-color!) ; any additional fields
  47. ; ((name color) ; element pattern
  48. ; (a 'red) ; the elements themselves
  49. ; (b 'green)
  50. ; (c 'puce)
  51. ; (d 'taupe)))
  52. ;
  53. ; (foo a) -> #{foo a}
  54. (define-syntax define-finite-type
  55. (lambda (form rename compare)
  56. (let ((destruct (lambda (proc)
  57. (apply proc (cdr form))))
  58. (%define-record-type (rename 'define-record-type))
  59. (%define-record-discloser (rename 'define-record-discloser))
  60. (%define (rename 'define))
  61. (%begin (rename 'begin))
  62. (%lambda (rename 'lambda))
  63. (%vector (rename 'vector))
  64. (%list (rename 'list))
  65. (%define-dispatch (rename 'define-dispatch))
  66. (%make-immutable! (rename 'make-immutable!))
  67. (%maker (rename 'maker))
  68. (%name (rename 'name))
  69. (%index (rename 'index))
  70. (%blah (rename 'blah)))
  71. (destruct (lambda (foo :foo pattern foo? foo-elements foo-name foo-index
  72. . more)
  73. (let* ((fields (do ((more more (cdr more))
  74. (fields '() (cons (car more) fields)))
  75. ((or (null? more)
  76. (pair? (caar more)))
  77. (reverse fields))))
  78. (elts (car (reverse more)))
  79. (names (map car elts)))
  80. `(,%begin
  81. (,%define-record-type ,foo ,:foo
  82. (,%maker ,%name ,%index . ,pattern)
  83. ,foo?
  84. (,%name ,foo-name)
  85. (,%index ,foo-index)
  86. . ,fields)
  87. (,%define-record-discloser ,:foo
  88. (,%lambda (,%blah)
  89. (,%list ',foo (,foo-name ,%blah))))
  90. (,%define ,foo-elements
  91. (,%make-immutable!
  92. (,%vector . ,(do ((elts elts (cdr elts))
  93. (i 0 (+ i 1))
  94. (res '() `((,%maker ',(caar elts)
  95. ,i
  96. . ,(cdar elts))
  97. . ,res)))
  98. ((null? elts)
  99. (reverse res))))))
  100. (,%define-dispatch ,foo ,names ,foo-elements)))))))
  101. (define-record-type define-record-discloser define-dispatch
  102. define begin lambda vector list))
  103. ; (define-dispatch <name> (<member name> ...) <vector of members>)
  104. ;
  105. ; This defines <name> to be a macro (<name> X) that looks X up in
  106. ; the list of member names and returns the corresponding element of
  107. ; <vector of members>.
  108. ;
  109. ; (define-dispatch foo (a b c) members)
  110. ; (foo b) -expands-into-> (vector-ref members 1)
  111. (define-syntax define-dispatch
  112. (lambda (form0 rename0 compare0)
  113. (let ((name (cadr form0))
  114. (names (caddr form0))
  115. (elts (cadddr form0))
  116. (%vector-ref (rename0 'vector-ref))
  117. (%code-quote (rename0 'code-quote)))
  118. `(define-syntax ,name
  119. (lambda (form1 rename1 compare1)
  120. (let ((elt (cadr form1)))
  121. (let loop ((names ',names) (i 0))
  122. (cond ((null? names)
  123. form1)
  124. ((compare1 elt (car names))
  125. (list (,%code-quote ,%vector-ref) (rename1 ',elts) i))
  126. (else
  127. (loop (cdr names) (+ i 1))))))))))
  128. (vector-ref code-quote))
  129. ; (define-enumerated-type <id and dispatch-macro>
  130. ; <type name>
  131. ; <predicate>
  132. ; <vector of elements>
  133. ; <name accessor>
  134. ; <index accessor>
  135. ; (<element name> ...))
  136. ;
  137. ; This is a simplified version that has no additional fields. It avoids
  138. ; a lot of unnecessary parens around the element names.
  139. ;
  140. ; The above expands into:
  141. ;
  142. ; (define-finite-type <id and dispatch-macro>
  143. ; <type name>
  144. ; <predicate>
  145. ; <vector of elements>
  146. ; <name accessor>
  147. ; <index accessor>
  148. ; ((name)
  149. ; (<element name>)
  150. ; ...))
  151. (define-syntax define-enumerated-type
  152. (syntax-rules ()
  153. ((define-enumerated-type id type-name predicate elements
  154. name-accessor index-accessor
  155. (element ...))
  156. (define-finite-type id type-name () predicate elements
  157. name-accessor index-accessor
  158. ((element) ...)))))