'Can the way in which a function is called depend on its arguments?
In Common Lisp, is there a way for an argument to a function to determine how the function is called, in the following sense? Let's say we have a function which has alredy been defined, say (defun foo (n) (+ 3 n)) and we want to define an iterative calls form ic which works in the following way:
(foo 6) => 9
(foo (ic 3 6)) => (foo (foo (foo 6))) => 15
(foo (ic 4 6)) => (foo (foo (foo (foo 6)))) => 18
Can this be done without redefining the function foo? Clearly ic needs to influence a function call outside itself.
Solution 1:[1]
By default no. That will change the semantics of the language: It will change what programs mean in the language. That said, you can define macros with such features but then, that will a domain specific language.
Macros are the designated tool for situations where you want to create forms with a different evaluation order from standard procedures.
To achieve the iterated function you want, you can simply define a function which takes a function func and an integer n then, returns a function which applies func n times to its arguments.
(defun iterate-function (func n)
"return a function which applies func n times to its argument.
(funcall (ic f 3) 0) => (f (f (f 0)))"
(unless (and (plusp n) (integerp n))
(error "n must be a non-negative integer"))
(let ((fns (make-list (1- n) :initial-element func)))
#'(lambda (&rest args)
(reduce #'funcall fns :initial-value (apply func args)))))
Now, we can create an iterated function like so:
CL-USER> (ic #'(? (x) (* x x)) 3)
#<FUNCTION (LAMBDA (&REST ARGS) :IN IC) {100A67B6DB}>
We can now apply the iterated function to arguments like so:
CL-USER> (funcall (ic #'(? (x) (* x x)) 3) 2)
256
Solution 2:[2]
One, possibly complex, way would be to define a macro BAR which would rewrite code.
Source:
(bar (foo (ic 3 6)))
Rewrite:
(foo (foo (foo 6)))
The macro BAR might need a code walker to transform more complex Lisp code like:
(bar
(let ((arg 6))
(foo (ic 3 arg))))
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Xero Smith |
| Solution 2 | Rainer Joswig |
