So far, solutions have worked less optimally in the R6RS / R7RS environment. I was thinking about generics when I started playing with this, but I didn't want to roll back my own type system. Instead, you provide a predicate procedure that should ensure that the arguments are appropriate for that particular procedure. It is not perfect, but works similarly to other R5RS answers, and you never redefine procedures.
I wrote everything in R6RS, but I think it is easy to port to R7RS. Here is an example:
#!r6rs (import (sylwester generic) (rename (rnrs) (+ rnrs:+)) (only (srfi :43) vector-append)) (define-generic + rnrs:+) (add-method + (lambda x (string? (car x))) string-append) (add-method + (lambda x (vector? (car x))) vector-append) (+ 4 5) ; ==> 9 (+ "Hello," " world!") ; ==> "Hello, world!" (+ '#(1) '
As you can see, I import + different name, so I do not need to redefine it (which is unacceptable).
Here is the library implementation:
#!r6rs (library (sylwester generic) (export define-generic add-method) (import (rnrs)) (define add-method-tag (make-vector 1)) (define-syntax define-generic (syntax-rules () ((_ name default-procedure) (define name (let ((procs (list (cons (lambda x #t) default-procedure)))) (define (add-proc id pred proc) (set! procs (cons (cons pred proc) procs))) (add-proc #t (lambda x (eq? (car x) add-method-tag)) add-proc) (lambda x (let loop ((procs procs)) (if (apply (caar procs) x) (apply (cdar procs) x) (loop (cdr procs)))))))))) (define (add-method name pred proc) (name add-method-tag pred proc)))
As you can see, I use messaging to add additional methods.
Sylwester
source share