我的任务是使用宏 do-primes计算a和b之间所有素数的列表,然后使用自定义代码打印它们.
说(do-primes(n 5 15)(鲜线)(princ n))应该打印4行:
这是我的代码:
(defun is-prime (n &optional (d (- n 1)))
(or (= d 1)
(and (/= (rem n d) 0)
(is-prime n (- d 1)))))
(defun my-func (a b)
(let (lst '())
(loop for i from a to b do
(if (is-prime i)
(push i lst)
)
)
(reverse lst))
)
(defmacro do-primes ((var startv endv) &body body)
`(my-func ,startv ,endv) `(,@body)
)
(do-primes (n 5 15) (fresh-line) (princ n))
Run Code Online (Sandbox Code Playgroud)
但是,当我运行代码时,我有这个错误:
EVAL :( FRESH-LINE)不是函数名称; 尝试使用符号代替
任何想法如何使这段代码正常工作?
请记住:宏转换代码.
如果你有像这样的代码
(do-primes (n 5 15)
(fresh-line)
(princ n))
Run Code Online (Sandbox Code Playgroud)
您应该问自己的第一个问题是:转换后的代码应该是什么样的?然后将实际运行的代码.
一旦你知道目标代码应该是什么样子,你就可以编写翻译.
Lisp有类似的宏:dolist和dotimes.你可以检查他们的宏扩展.上面有几种方法可以实现.一种是为身体使用功能和闭合.通常,在Lisp中,虽然我希望它们扩展到一些执行循环迭代的低级代码.
在伪代码表示法中,更高级的编码方法是:
for n from n below/upto 15
when is-prime (n)
do fresh-line () and princ (n)
Run Code Online (Sandbox Code Playgroud)
所以do-primes宏需要扩展为类似的代码 - 但Lisp代码.许多其他方法也是可能的.
你的代码
(defmacro do-primes ((var startv endv) &body body)
`(my-func ,startv ,endv)
`(,@body))
Run Code Online (Sandbox Code Playgroud)
您的宏有两个子表单.为什么?计算第一个表格然后返回到无处.结果将被垃圾收集,因为它没有被使用.
第二种形式
`(,@body)`
Run Code Online (Sandbox Code Playgroud)
将被计算,返回值将是返回的代码.这样没有意义.括号不对语句进行分组,也没有迭代.