Question 1 @ 2024-11-26 18:29
We have seen how “mainstream” macros like
#define square(x) x * x
fail miserably. What’s the “root cause” of these failures?
- There’s no problems with these macros: it’s just that different languages behave differently.
- The problem is that C is an infix language.
-
The problem is in the macro body, it should be
((x)*(x))
. - The problem is that these macros are oblivious to the AST of the expressions they handle.
- Macros can only really work with languages in the Lisp family.
Question 2 @ 2024-11-26 18:31
Why do we say that Racket/Scheme (and others) macros are “Hygienic”?
- They respect the expression structure.
- They are used for “clean” code in functional languages.
- They respect lexical scope and avoid capturing identifiers.
- They respect dynamic scope and avoid capturing identifiers.
- They prevent possible side-effects at the macro level.
Question 3 @ 2024-11-26 18:33
Given the following alternative definitions of a while
facility:
(define (while condition-thunk body-thunk)
(when (condition-thunk)
(body-thunk)
(while condition-thunk body-thunk)))
(define-syntax-rule (while condition body ...)
(when condition
body ...
(while condition body ...)))
(when (condition-thunk)
(body-thunk)
(while condition-thunk body-thunk)))
(define-syntax-rule (while condition body ...)
(when condition
body ...
(while condition body ...)))
Choose the true statement.
- They are both correct and completely equivalent.
- They are both leading to an infinite loop.
- The first is a function and the second is a macro, so they cannot be compared in any way.
- The macro definition is fundamentally better since the function version can accept only a single body expression.
- The macro definition is broken since it’s an infinite loop, the function version is inconvenient to use but it works fine.
-
The macro definition is broken since it’s an infinite loop, the
function version is broken since it takes one
body-thunk
argument.
Question 4 @ 2024-11-26 18:37
Consider the following macro and use:
(define-syntax for
(syntax-rules (= to do)
[(for x = m to n do body ...)
(letrec ([loop (lambda (x)
(when (<= x n)
body ...
(loop (+ x 1))))])
(loop m))]))
(let ([i 9])
(for i = 1 to (add1 i) do (printf "~s\n" i)))
(syntax-rules (= to do)
[(for x = m to n do body ...)
(letrec ([loop (lambda (x)
(when (<= x n)
body ...
(loop (+ x 1))))])
(loop m))]))
(let ([i 9])
(for i = 1 to (add1 i) do (printf "~s\n" i)))
This prints integers going up from 1 and never stops.
What’s the problem?
-
It’s yet another example of a bad macro (like
while
from the previous question) that leads to an infinite loop. -
The outer
(let ([i 9]) ...)
messes up the scope. - The use of the macro doesn’t follow the expected shape WRT the listed keywords.
-
The
n
argument to the macro is inside the scope of the(lambda (x) ...)
, making the(add i)
refer to the loop variable.