home *** CD-ROM | disk | FTP | other *** search
- ;; A mechanism for defining an ordering of procedures.
- ;; This is used to order descriminator predicates
- ;; used in the declarations of generic functions.
- ;;
- (define (is-a a b)
- (if (not (eq? a b))
- (if (is-a? b a)
- (error 'circular-subclassing)
- (set-procedure-property! a
- 'is-a
- (cons b (or (procedure-property a 'is-a)
- '()))))))
- (define (is-a? a b)
- (cond
- ((eq? a b) #t)
- ((eq? b #t) #t)
- ((member b (procedure-property a 'is-a)) #t)
- ((or-map (lambda (p) (is-a? p b)) (procedure-property a 'is-a)) #t)
- (#t #f)))
-
-
- (define (make-lock mechanism locked) (cons mechanism locked))
- (define (open-lock? lock key locked) (and lock
- (eq? locked (cdr lock))
- ((car lock) lock key)))
-
-
- ;; A method is represented by a list: (<signature> <procedure>)
- ;; These are orded by comparing signatures. Normally, a signature
- ;; is a list of descriminator procedures, ordered lexically by IS-A?.
- ;;
- (define (default-method-ordering a b)
- (set! a (car a))
- (set! b (car b))
- (let loop ((a a)
- (b b))
- (cond
- ((and (null? a) (null? b)) #f)
- ((null? a) #t)
- ((null? b) #f)
- ((not (pair? a)) (cond ((not (pair? b)) (is-a? a b))
- (else #f)))
- ((not (pair? b)) #t)
- ((eq? (car a) (car b)) (loop (cdr a) (cdr b)))
- ((is-a? (car a) (car b)) #t)
- ((is-a? (car b) (car a)) #f)
- (else (loop (cdr a) (cdr b))))))
-
-
- ;; The default action of a generic function:
- ;;
- (define (default-method . args)
- (apply error 'not-implemented args))
-
-
- ;; If method-case (a list (<sig> <proc>)) applies
- ;; to args, return method-case, else return #f.
- ;;
- (define (method-case-applies method-case args)
- (let loop ((preds (car method-case))
- (args args))
- (cond
- ((and (pair? preds)
- (pair? args)
- (or (eq? #t (car preds))
- ((car preds) (car args))))
- (loop (cdr preds) (cdr args)))
- ((and (null? preds)
- (null? args))
- method-case)
- ((and (not (null? preds))
- (procedure? preds)
- (preds args))
- method-case)
- ((eq? #t preds) method-case)
- (else #f))))
-
- (begin
- (define generic-things
- (let* ((alist-set! (alist-associator eq?))
- (secret (cons 'generic 'secret))
- (secret? (lambda (x) (eq? secret x)))
- (test-lock (lambda (lock key) (secret? key))))
-
- (letrec ((tag-basic-generic (lambda (proc mop)
- (set-procedure-property! proc
- tag-basic-generic
- (make-lock test-lock proc))
- (set-procedure-property! proc test-lock mop)
- proc))
- (basic-generic? (lambda (obj)
- (and (procedure? obj)
- (open-lock? (procedure-property obj tag-basic-generic)
- secret
- obj))))
- (basic-mop (lambda (generic) (and (basic-generic? generic)
- (procedure-property generic test-lock))))
- (basic-make-generic (lambda args
- (let ((mop-options (if args (car args) '()))
- (args (and args (cdr args))))
- (letrec ((state #f)
- (mop (or (kw-arg-ref mop-options :mop-method)
- (lambda (protocol generic . args)
- (case protocol
- ((init)
- (apply (or (kw-arg-ref mop-options :init)
- (lambda (state mop)
- (mop 'set-state! #f (cons '() '()))
- (let ((d (mop 'dispatcher #f)))
- (tag-basic-generic d mop)
- d)))
- state generic args))
-
- ((add-method!)
- (apply (or (kw-arg-ref mop-options :add-method!)
- (lambda (state generic sig method)
- (set-car! state
- (alist-set! (car state)
- sig
- (list method)))
- (set-cdr! state #f)))
- state generic args))
- ((method-ordering)
- (apply (or (kw-arg-ref mop-options :method-ordering)
- (lambda (g)
- default-method-ordering))
- generic args))
- ((register-methods)
- (apply (or (kw-arg-ref mop-options :register-methods)
- (lambda (state generic)
- (set-cdr! state
- (sort (car state)
- (mop 'method-ordering
- generic)))))
- state generic args))
- ((dispatcher)
- (apply (or (kw-arg-ref mop-options :dispatcher)
- (lambda (state generic)
- (lambda args
- (if (not (cdr state))
- (mop 'register-methods generic))
- (let ((method
- (or-map
- (lambda (mc)
- (method-case-applies mc args))
- (cdr state))))
- (if (not method)
- (error 'no-applicable-method args))
- (apply (cadr method) args)))))
- state generic args))
- ((set-state!)
- (apply (or (kw-arg-ref mop-options :set-state!)
- (lambda (old-state generic new-state)
- (set! state new-state)))
- state generic args))
-
- ((state)
- (apply (or (kw-arg-ref mop-options :set-state!)
- (lambda (state generic) state))
- state generic args))
- (else (let ((f (kw-arg-ref mop-options
- (symbol->keywork protocol))))
- (apply (or f default-method)
- state generic args))))))))
- (apply mop 'init mop args))))))
- (list basic-make-generic basic-mop basic-generic?))))
-
- (define basic-make-generic (car generic-things))
- (define basic-generic-mop (cadr generic-things))
- (define basic-generic? (caddr generic-things)))
-
-
- (define (basic-meta-object-protocol prot obj . args)
- (let ((mop (basic-generic-mop obj)))
- (apply mop prot obj args)))
- (define (basic-add-method! obj sig proc . args)
- (apply basic-meta-object-protocol 'add-method! obj sig proc args))
- (define (basic-register-methods obj . args)
- (apply basic-meta-object-protocol 'register-methods obj args))
-
- (define (generalize-basic-method op)
- (let ((gen (basic-make-generic)))
- (basic-add-method! gen #t op)
- gen))
-
- (define make-generic (generalize-basic-method basic-make-generic))
- (define generic-mop (generalize-basic-method basic-generic-mop))
- (define generic? (generalize-basic-method basic-generic?))
- (define add-method! (generalize-basic-method basic-add-method!))
- (is-a basic-generic? generic?)
- (provide 'generics)
-