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?
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.