Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
tutorials:advanced:cram-macros [2022/04/10 22:32] – [Syntax] lucatutorials:advanced:cram-macros [2022/04/10 23:34] (current) luca
Line 1: Line 1:
-===== Defining new macros =====+====== Defining new macros======
  
-Disclamer+Disclaimer
 A general rule of thumb is to try and not define new macros if they are not needed, or if they do not serve a specific purpose, since, while they do make the code more readable in some cases, they also make it way harder to debug the code. A general rule of thumb is to try and not define new macros if they are not needed, or if they do not serve a specific purpose, since, while they do make the code more readable in some cases, they also make it way harder to debug the code.
  
-====== Defining new macros====== 
 ===== Syntax =====  ===== Syntax ===== 
  
Line 14: Line 13:
                                                        
 Macros are used to extend the syntax of standard LISP by generating/transforming code and adding new notations. Macros are used to extend the syntax of standard LISP by generating/transforming code and adding new notations.
-One important thing to note is that the computation of the body is already done at compile time and that it is possible to even quote LISP expressions, which enables us to generate code during compile-time. +One important thing to note is that the computation of the body is already done at compile time and that it is possible to even quote LISP expressions, which enables us to generate code through macro-expansion, which happens during compile-time. 
 For example: For example:
  
Line 57: Line 56:
 If we need to remove the outermost parenthesis, for example, to put the code contained into a (progn ...) block, then we can use ,@ to splice the list. You can find an example of how to use this in line 4 of the measure-time macro. If we need to remove the outermost parenthesis, for example, to put the code contained into a (progn ...) block, then we can use ,@ to splice the list. You can find an example of how to use this in line 4 of the measure-time macro.
  
 +===== Example of an CRAM-macro =====
 +<code lisp>
 +CL-USER> (defmacro with-simulated-robot (&body body)
 +          `(let ((results
 +                   (proj:with-projection-environment urdf-bullet-projection-environment
 +                     (cpl-impl::named-top-level (:name :top-level)
 +                       ,@body))))
 +             (car (cram-projection::projection-environment-result-result results))))
 +</code>
 +
 +When analyzing this macro the first thing we can notice is that we only have (&body body) as our parameter list. This means, that this macro will be used as a prefix to code that we want to run on our robot. For example:
 +
 +<code lisp>
 +CL-USER> (with-simulated-robot
 +            code that does awesome stuff)
 +</code>
 +
 +Here, "body" would now contain "(code that does awesome stuff)"
 +So now let's go through what the macro actually does. The first thing that is done, is to signal to LISP that a backquoted expression is about to start. Here, a variable "results" is created, which contains two nested, quoted functions/macros, as well as our spliced, evaluated body. The code contained by our variable "result" will look roughly like this:
 +
 +<code lisp>
 +'(proj:with-projection-environment ... 
 +   '(cpl-impl::named-top-level ...
 +      evaluation of our code that does awesome stuff))
 +</code>
 +
 +Those two functions/macros will only be evaluated at runtime, as we can see from the quotes (').
 +After defining result, let's see roughly how the body of our macro will expand. Since non of the expressions have a comma (,) in front of them, every function/macro will be treated as if they were quoted ('):
 +
 +<code lisp>
 +'(car '(cram-projection::projection-environment-result-result ...))
 +</code>
 +
 +To conclude: without any prior knowledge of what the other functions/macros are doing we can tell, that this macro will try to evaluate the body as far as it can during macro expansion. The results will be passed onto other functions/macros, which are all evaluated during runtime, which makes sense, given that the macro name is "with-simulated-robot", which gives the impression that the code will be run while a robot is being simulated, which can obviously only happen during runtime, and not during macro expansion.