Is it possible to "extend" a function / lambda / macro in Scheme?
inheritance, r5rs, r6rs, r7rs, scheme
Solution
Rather than using `import`, a better solution is to keep track of the original function by `let`-binding it. It's also better to check that the type of the argument is a string, rather than that it is not a number. Using both of these approaches means that it's possible to compose the technique.
(define +
(let ((old+ +))
(lambda args
(if (string? (car args))
(apply string-append args)
(apply old+ args)))))
(define +
(let ((old+ +))
(lambda args
(if (vector? (car args))
(apply vector-append args)
(apply old+ args)))))
The above will produce a `+` function that works on numbers, strings, or vectors. In general, this is a more extensible approach.
I was able to verify that the above works correctly in MIT/GNU Scheme, Guile, Racket, Chicken, TinyScheme, and SCSH. However, in some implementations, such as Biwa Scheme, it is necessary to use `set!` instead of `define`. In Ikarus, `set!` cannot be used on an imported primitive, and `define` messes up the environment, so it is necessary to do this in two steps:
(define new+
(let ((old+ +))
(lambda args
(if (string? (car args))
(apply string-append args)
(apply old+ args)))))
(define + new+)
Note that according to R5RS, `define` and `set!` are supposed to be equivalent in this case:
At the top level of a program, a definition
(define <variable> <expression>)
has essentially the same effect as the assignment expression
(set! <variable> <expression>)
if `<variable>` is bound.
Problem
For example: if I want the function `equal?` recognize my own type or record, can I add a new behavior of `equal?`? without erasing or overwriting the old one? Or for example if I want to make the function `"+"` accept also string?