Search code examples
macroslispcommon-lispmetaprogramming

Common LISP - How to return statement


I'm currently trying to learn how to program in "Common Lisp". Therefore, I'm currently dealing with a minor problem regarding the definition of macros. Said macro should work as follows: It takes a list of numbers, creates a temporary (initially empty) list which is populated with the squared numbers and returns it. Unfortunately, I have some problems with this source code.

    (defmacro square_loop (args)
        (let ((res ()))
            (loop for x in args
                do (push (* x x) res))
            res
        )
    )

Regarding error messages, I think that the error is that I don't return a list but a function call which has the same content as the list. However, it would be evaluated as a function call which is not correct. Is there any way how I can write the macro correctly?

EDIT
I know that I could technically solve this problem with utilizing functions like mapcar. However, I wanted to see if my idead of a macro was even possible.


Solution

  • I think you don't understand what macros are and what's their use case. I suggest you to read materials like

    7. Macros: Standard Control Constructs

    8. Macros: Defining Your Own

    2.4.6 Backquote + comma (operators used in my solution)

    Usually, you use macros for transformations of source code or situations, when you want to control when (and if ever) something evaluates. You should avoid macros if your problem can be solved with a function. And I don't see any reason to use a macro for squaring every number in the list.

    But just for learning purposes...

    (defmacro square-loop (args)
      (let ((res '()))
        (loop for x in args
              do (push (* x x) res))
        `',res))
    
    > (square-loop (1 2 3))
    (9 4 1)
    

    Notice three things:

    • kebab-case (square_loop -> square-loop)
    • proper formatting of parentheses
    • push pushes every element in the front of the list, so the final result is actually reversed- I'm not sure whether you want it, so here is a similar solution without reversing:
    (defmacro square-loop (args)
      `',(mapcar (lambda (x) (* x x)) args))
    
    > (square-loop (1 2 3))
    (1 4 9)