This is a read-only archive of lispforum.com. The forum was locked to new users and posts and is preserved here as static HTML from a database snapshot taken on 2019-09-07.

macro for looping over functions in a list

13 posts · 3854 views

Given
(defconstant functions
  '(1+
    1-))
,

I want to define a macro that expands into
(+
(1+ 1)
(1- 1))
How do I manage this?

Re: macro for looping over functions in a list

Looping over a list of functions does not require a macro. It is unclear to me what you are trying to achieve.

Re: macro for looping over functions in a list

I want the functions to be called to be inlined.

Re: macro for looping over functions in a list

That looks like a probably unnecessary micro-optimization, but if you want to use a constant at compile time you have to wrap it in EVAL-WHEN to guarantee it is available at compile time, and then just use it.

Re: macro for looping over functions in a list

It appears that standard functions like MAP and REDUCE may solve your problem. A good implementation (for optimization) should have a compiler macro that identifies when these functions are passed constant parameters and can then inline the function calls for you.

What do the benchmarks look like without this inlined?

Re: macro for looping over functions in a list

imba wrote:I want the functions to be called to be inlined.
You don't need to worry about inlining simple standard functions. The functions 1+ and 1- are already inlined in most (all?) implementations.

If you created a function and want it to be inlined, use declaim
(defun my-function (...)
  ...)

(declaim (inline myfunction))

Re: macro for looping over functions in a list

In the following code,
(defconstant functions '(1+ 1-)) 
(defun foo ()
  (loop for fun in functions 
           summing (funcall fun 4)))
1+ and 1- aren't inlined in foo. How can I achieve this?

Re: macro for looping over functions in a list

Only explicit calls to a function can be inlined. If you are holding functions in a variable, how can the compiler know which function that variable will be holding so that it can inline it? Unless the compiler makes really extraordinary analysis.

You can, however, optimize your code a little bit. The functions 1+ and 1- are supposed to work on integers, floats, rationals, complexes, etc. You can create your own version:
(defun fixnum-1+ (x)
  (1+ (the fixnum x)))

(defun fixnum-1- (x)
  (1- (the fixnum x)))

(defconstant +functions+ '(fixnum-1+ fixnum-1-)) 
(defun foo ()
  (loop for fun in +functions+ 
           summing (funcall fun 4)))
Note that it is convention to use '+' around the name of constants, like +this+.

Re: macro for looping over functions in a list

gugamilare wrote:Only explicit calls to a function can be inlined. If you are holding functions in a variable, how can the compiler know which function that variable will be holding so that it can inline it?
Well, because +functions+ is a constant? Is there no possibility to write a macro that translates this code to
(+ (funcall 1+ 4)
    (funcall 1- 4))
?

Re: macro for looping over functions in a list

Except the EVAL-WHEN issue I mentioned earlier this is a trivial list manipulation problem. If you don't know how to do that, you probably shouldn't be worrying about it, since, as it has been said, this is a microoptimization which is unlikely to achieve anything significant in most cases.

Re: macro for looping over functions in a list

So what's wrong with the following code?
(defconstant +Functions+ '(1+ 1-))

(defun compile-Function (Function)
  `((let ((val (funcall ,Function 4)))
          (if (>= val 0)
              val
            (return-From evaluate -100)))))

(defun compile-Functions (Functions)
  `(defun evaluate ()
     (+ ,@(loop for Function from Functions
               append (compile-Function Function)))))

Re: macro for looping over functions in a list

Looping in a list is achieved with IN keyword, not FROM, which is numeric. And if you want to funcall by name then you need to quote your symbols, although I thought the point of this was to call the function directly? Also, indirect dependency on block name like this is bad style. And there are problems with variable capture. Something like this will work when used as a macroexpander function:
(eval-when (:execute :compile-toplevel :load-toplevel)
  (defconstant +functions+ '(1+ 1-)))

(defun compile-function (function block-name)
  (let ((val (gensym)))
   `((let ((,val (,function 4)))
       (if (>= ,val 0)
           ,val
           (return-from ,block-name -100))))))

(defun compile-functions (functions)
  `(defun evaluate ()
     (+ ,@(loop for function in functions
                append (compile-function function 'evaluate)))))
On Lisp by Paul Graham explains a lot about macro programming, and it is available for free.

Re: macro for looping over functions in a list

Thank you very much for your patience!