'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