Advertisement
Guest User

zoz

a guest
Aug 29th, 2017
193
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Racket 7.35 KB | None | 0 0
  1. ;; curry*
  2. ;; like curry but will never fully apply and will instead make a
  3. ;; thunk
  4. (define (curry* . args)
  5.   (lambda rest-args
  6.     (apply (first args)
  7.            (append (rest args) rest-args))))
  8.  
  9. ;; make-obj
  10. ;; make a classless singleton object
  11. ;; state:
  12. ;;;; list of pairs, each pair's car is the variable name and cdr is
  13. ;;;; the default value
  14. ;; methods:
  15. ;;;; list of pairs, each pair's car is the method name and cdr is
  16. ;;;; the implementation which must be a function that takes the
  17. ;;;; receiver and its state key (see below) and may take other
  18. ;;;; arguments
  19. ;; return value can be used as follows:
  20. ;; (retval 'method-name method-args...)
  21. ;; note that methods are in fact stored directly in the object and
  22. ;; not in a vtable; this is deliberate because objects can be
  23. ;; extended with new methods via the 'def pseudomethod
  24. (define (make-obj state methods)
  25.   (letrec
  26.     ;; state-key
  27.     ;; a unique symbol allowing access to the object's private
  28.     ;; variables
  29.     ;; will be passed to methods as second parameter after the
  30.     ;; receiver itself and can be used as follows:
  31.     ;; (receiver state-key 'variable-name) -- to get variable
  32.     ;; (receiver state-key 'variable-name 'value) -- to set variable
  33.     ([state-key (gensym)]
  34.      [self
  35.       (lambda (method . args)
  36.         (cond
  37.           [(eq? method state-key)
  38.            (case (length args)
  39.              [(0) state]
  40.              [(1)
  41.               (let ([found (assoc (first args) state)])
  42.                 (unless found
  43.                   (raise-arguments-error state-key
  44.                     "no such field"
  45.                     "field name" (first args)))
  46.                 (cdr found))]
  47.              [(2)
  48.               (set! state
  49.                 (cons (cons (first args) (second args))
  50.                       (remove (first args) state
  51.                               (lambda (a b) (eq? a (car b))))))])]
  52.           [(eq? method 'def)
  53.            (unless (= (length args) 2)
  54.              (raise-arguments-error state-key
  55.                "wrong number of arguments to define a method"
  56.                "arguments" args))
  57.            (set! methods
  58.              (cons (cons (first args) (second args))
  59.                    (remove (first args) methods
  60.                            (lambda (a b) (eq? a (car b))))))]
  61.           [else
  62.            (let ([found (assoc method methods)])
  63.              (unless found
  64.                (raise-arguments-error state-key
  65.                  "no such method"
  66.                  "method name" method))
  67.              (unless (procedure-arity-includes?
  68.                        (cdr found)
  69.                        (+ 2 (length args)))
  70.                (raise-arguments-error state-key
  71.                  "unsupported number of arguments"
  72.                  "method name" method
  73.                  "arguments" args
  74.                  "method arity" (procedure-arity (cdr found))))
  75.              (apply (curry* (cdr found) self state-key) args))]))])
  76.     self))
  77.  
  78. ;; make-class
  79. ;; make a class, which is a classless singleton object that can make
  80. ;; other objects homogeneously according to a stored blueprint and
  81. ;; identify whether or not any given datum is an object that came
  82. ;; from it
  83. ;; state, methods: same as for make-obj, but affects instances
  84. ;; class-state, class-methods: affects the class itself instead
  85. ;; superclass:
  86. ;;;; if specified, objects created via the class currently
  87. ;;;; being defined will belong to both it and also the class given
  88. ;;;; by this parameter, and will follow the stored blueprints of
  89. ;;;; both, but such that any methods defined in the "subclass" (the
  90. ;;;; class currently being defined) will take priority over those
  91. ;;;; that were in the "superclass"
  92. ;; return value can be used as follows:
  93. ;; (retval 'superclass) -- returns the superclass or #f if none
  94. ;; (retval 'alloc) -- instantiates the class but doesn't call 'init
  95. ;; (retval 'new args...) -- instantiates the class and forwards the
  96. ;; rest of the args to a call to 'init if the class defines any such
  97. ;; method
  98. ;; (retval '? obj) -- returns whether the given object or other
  99. ;; datum is an object of this class
  100. (define (make-class state methods
  101.          #:class-state [class-state `()]
  102.          #:class-methods [class-methods `()]
  103.          #:superclass [superclass #f])
  104.   (letrec
  105.     ([class-key (gensym)]
  106.      [init-proc
  107.       (let ([found (assoc 'init methods)])
  108.         (if found (cdr found) void))]
  109.      [super-proc
  110.       (lambda (self @ . args)
  111.         (unless superclass
  112.           (raise-arguments-error class-key
  113.             "no superclass to call"
  114.             "arguments" args))
  115.         (apply
  116.           (curry* (superclass 'init-proc)
  117.                   self @) args))]
  118.      [self
  119.       (make-obj class-state
  120.         (append class-methods
  121.           `((init-proc .
  122.              ,(lambda (self @) init-proc))
  123.             (superclass .
  124.              ,(lambda (self @) superclass))
  125.             (alloc .
  126.              ,(lambda (self @)
  127.                 (if superclass
  128.                   (let ([retval (superclass 'alloc)])
  129.                     (retval 'def class-key
  130.                       (lambda (self @) @))
  131.                     (retval 'def 'super super-proc)
  132.                     (map (lambda (p)
  133.                            (retval (retval class-key)
  134.                                    (car p) (cdr p))) state)
  135.                     (map (lambda (p)
  136.                            (retval 'def (car p) (cdr p)))
  137.                          methods)
  138.                     retval)
  139.                   (make-obj state
  140.                     (append
  141.                       `((,class-key . ,(lambda (self @) @))
  142.                         (super . ,super-proc))
  143.                       methods)))))
  144.             (instance-init .
  145.              ,(lambda (self @ obj . args)
  146.                 (unless (self '? obj)
  147.                   (raise-arguments-error class-key
  148.                     "can't initialize non-instance"
  149.                     "non-instance" obj
  150.                     "arguments" args))
  151.                 (let ([found (assoc 'init methods)])
  152.                   (when found
  153.                     (apply
  154.                       (curry* (cdr found) obj (obj class-key))
  155.                       args)))))
  156.             (new .
  157.              ,(lambda (self @ . args)
  158.                 (letrec
  159.                   ([retval (self 'alloc)])
  160.                   (apply
  161.                     (curry* init-proc retval
  162.                       (retval class-key))
  163.                     args)
  164.                   retval)))
  165.             (? .
  166.              ,(lambda (self @ obj)
  167.                 (with-handlers
  168.                   ([exn:fail:contract? (lambda args #f)])
  169.                   (obj class-key)
  170.                   #t))))))]) self))
  171.  
  172. ;; usage examples
  173. (define counter
  174.   (make-class `((a . 0))
  175.     `((inc .
  176.        ,(lambda (self @)
  177.           (self @ 'a (add1 (self @ 'a)))
  178.           (self @ 'a))))))
  179. (define bidirectional-counter
  180.   (make-class #:superclass counter `()
  181.     `((dec .
  182.        ,(lambda (self @)
  183.           (self @ 'a (sub1 (self @ 'a)))
  184.           (self @ 'a))))))
  185. (define n (counter 'new))
  186. (define m (bidirectional-counter 'new))
  187. (display (counter '? n)) (newline) ;; #t
  188. (display (counter '? m)) (newline) ;; #t
  189. (display (bidirectional-counter '? n)) (newline) ;; #f
  190. (display (bidirectional-counter '? m)) (newline) ;; #t
  191. (display (n 'inc)) (newline) ;; 1
  192. (display (m 'inc)) (newline) ;; 1
  193. (display (m 'dec)) (newline) ;; 0
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement