/utilities/proletariat.rkt

http://github.com/VincentToups/racket-lib · Racket · 212 lines · 180 code · 27 blank · 5 comment · 7 complexity · 51c9a2f08246e9b21bffccaa8f95bc52 MD5 · raw file

  1. #lang racket
  2. (require (planet "main.ss" ("murphy" "multimethod.plt" 2 1))
  3. functional/point-free
  4. racket/match
  5. racket/dict)
  6. (define-multimethod (at obj field) :: (vector-immutable (class-name obj) (class-name field)))
  7. (define-method (at obj field) :: #(object symbol)
  8. (dict-ref obj field))
  9. (define (class-table class . args)
  10. (let loop [(object (make-immutable-hash (list (cons 'class class))))
  11. (args args)]
  12. (match args
  13. [(list) object]
  14. [(cons key (cons val rest))
  15. (loop (dict-set object key val) rest)])))
  16. (define (-> d . keys)
  17. (let loop ((d d)
  18. (keys keys))
  19. (match keys
  20. [(list) d]
  21. [(cons key rest)
  22. (loop (at d key) rest)])))
  23. (define object (class-table 'object ))
  24. (define (object? thing)
  25. (derived? (class-name thing) 'object))
  26. (define (dict-fold f-key-val-ac init d)
  27. (let loop ([ac init]
  28. [pos (dict-iterate-first d)])
  29. (if (not pos) ac
  30. (loop (f-key-val-ac (dict-iterate-key d pos)
  31. (dict-iterate-value d pos)
  32. ac)
  33. (dict-iterate-next d pos)))))
  34. (define (dict-merge from into)
  35. (dict-fold
  36. (lambda (key val d)
  37. (dict-set d key val))
  38. into
  39. from))
  40. (define (class-name o)
  41. (match o
  42. [(? hash? immutable?)
  43. (dict-ref o 'class 'immutable-hash)]
  44. [(? list?) 'list]
  45. [(? vector?) 'vector]
  46. [(? string?) 'string]
  47. [(? number?) 'number]
  48. [(? struct?) 'struct]
  49. [(? symbol?) 'symbol]
  50. [(? char?) 'char]
  51. [(? boolean?) 'boolean]
  52. [(? keyword?) 'keyword]
  53. [(? pair?) 'pair]
  54. [(? hash?) 'hash]))
  55. (define derive-from-object (partial< derive 'object))
  56. (for-each derive-from-object
  57. '(dict list vector string number struct symbol char boolean keyword pair))
  58. (define derives-from derive)
  59. (define derives-from? derived?)
  60. (define (>> class parents . args)
  61. (let* ((new-fields (apply class-table class args))
  62. (merge-list (reverse (cons new-fields parents)))
  63. (class-dict (foldl dict-merge (car merge-list) (cdr merge-list))))
  64. (for-each (lambda (parent)
  65. (derive class (class-name parent))) parents)
  66. class-dict))
  67. (struct depending-on-data (keys lam) #:transparent)
  68. (define-syntax depending-on
  69. (syntax-rules ()
  70. [(depending-on (key/arg ...) body ...)
  71. (depending-on-data '(key/arg ...)
  72. (lambda (key/arg ...) body ...))]))
  73. (define (adjust* object . args)
  74. (match args
  75. [(list) object]
  76. [(cons key (cons val rest))
  77. (apply adjust (dict-set object key
  78. (if (depending-on-data? val)
  79. (apply (depending-on-data-lam val)
  80. (map
  81. (>partial at object)
  82. (depending-on-data-keys val)))
  83. val)) rest)]))
  84. (define (adjust object . args)
  85. (let ((original-object object))
  86. (let loop ((object object)
  87. (args args))
  88. (match args
  89. [(list) object]
  90. [(cons key (cons val rest))
  91. (loop (dict-set object key
  92. (if (depending-on-data? val)
  93. (apply (depending-on-data-lam val)
  94. (map
  95. (>partial at original-object)
  96. (depending-on-data-keys val)))
  97. val)) rest)]))))
  98. ;(define rock (>> 'rock (list object) 'type 'pyrite))
  99. ;(define-syntax define/class
  100. ; (syntax-rules ()
  101. ; [(define/class name-id (parents ...) field/val ...)
  102. ; (define name-id (>> 'name-id (list parents ...) field/val ...))]))
  103. (define-syntax (define/class stx)
  104. (define (append-? symb)
  105. (string->symbol (string-append (symbol->string symb) "?")))
  106. (syntax-case stx ()
  107. [(define/class name-id (parents ...) field/val ...)
  108. (with-syntax ([predicate-name (datum->syntax
  109. #'name-id
  110. (append-? (syntax->datum #'name-id)))])
  111. (syntax (begin
  112. (define name-id (>> 'name-id (list parents ...) field/val ...))
  113. (define (predicate-name o)
  114. (derived? (class-name o) 'name-id)))))]))
  115. (define (flat->dict lst)
  116. (let loop ([lst lst]
  117. [d (make-immutable-hash '())])
  118. (match lst
  119. [(list) d]
  120. [(cons key (cons val rest))
  121. (loop rest (dict-set d key val))])))
  122. (define (mix new-class-name from-class into-class . args)
  123. (let ((resolvers (flat->dict args)))
  124. (dict-fold
  125. (lambda (key new into-class)
  126. (let* ((resolver (dict-ref resolvers key (lambda () (lambda (new old) new))))
  127. (old (dict-ref into-class key #f)))
  128. (dict-set into-class key (resolver new old))))
  129. into-class
  130. from-class)))
  131. (define-multimethod (as ob class-nm) :: (vector-immutable (class-name ob) class-nm))
  132. (define-method (as o s) :: #(object string)
  133. (format "~a" o))
  134. (define-method (as o n) :: #(object number)
  135. (string->number o))
  136. (define-method (as n _) :: #(number number)
  137. n)
  138. (define-syntax with-a-slot
  139. (syntax-rules ()
  140. [(with-a-slot object (slot symbol) body ...)
  141. (let ((symbol (at object 'slot)))
  142. body ...)]
  143. [(with-a-slot object (slot) body ...)
  144. (let ((slot (at object 'slot)))
  145. body ...)]
  146. [(with-a-slot object slot body ...)
  147. (let ((slot (at object 'slot)))
  148. body ...)]))
  149. (define-syntax with-slots
  150. (syntax-rules ()
  151. [(with-slots object () body ...)
  152. (begin body ...)]
  153. [(with-slots object (binder binders ...) body ...)
  154. (let ((id object))
  155. (with-a-slot id binder
  156. (with-slots id (binders ...) body ...)))]))
  157. (define-match-expander -at
  158. (syntax-rules ()
  159. [(-at key pat)
  160. (app (lambda (id)
  161. (at id key)) pat)]))
  162. (define-match-expander obj
  163. (syntax-rules ()
  164. [(obj (key pat) ...)
  165. (and (-at key pat) ...)]))
  166. (provide define/class
  167. object
  168. >>
  169. derives-from
  170. derives-from?
  171. class-name
  172. dict-merge
  173. dict-fold
  174. class-table
  175. mix
  176. adjust
  177. adjust*
  178. depending-on
  179. ->
  180. as
  181. at
  182. with-slots
  183. with-a-slot
  184. obj
  185. (all-from-out (planet "main.ss" ("murphy" "multimethod.plt" 2 1))))