(mac extend (name arglist test . body) (w/uniq args `(let orig ,name (= ,name (fn ,args (aif (apply (fn ,arglist ,test) ,args) (apply (fn ,arglist ,@body) ,args) (apply orig ,args)))))))
extend redefines an existing function name. When the function is now called, first the code in test is run. If the test returns
nil, the original function definition is called as if the function had never been extended. But if the test succeeds, the code in body is run instead of the original function.
For example, here is an extension to
+ to combine tables:
(extend + args (isa (car args) 'table) (listtab (apply + (rev:map tablist args))))
arc> (+ (obj a 1) (obj b 2) (obj a 3 c 4)) #hash((b . 2) (c . 4) (a . 1))
The body is only called if the test “
(isa (car args) 'table)” succeeds. If the test fails, then the original
+ is called.
Within the body which is called if the test succeeds,
orig refers to the original function definition, and
it refers to the value returned by the test.
Both the test and the body see the arguments specified by arglist. For example,
arc> (def foo (x) (+ x 5)) #<procedure: foo>
arc> (extend foo (x) (even x) (+ x 1)) #<procedure: foo>
arc> (foo 1) 6
arc> (foo 2) 3
Or, using the hackinator:
hack ycombinator.com/arc/arc3.1.tar \ awwx.ws/extend0.arc
This code may be redistributed and modified under the same terms as Arc itself.