用宏运行函数

use*_*080 1 common-lisp

我的任务是使用 do-primes计算ab之间所有素数的列表,然后使用自定义代码打印它们.

(do-primes(n 5 15)(鲜线)(princ n))应该打印4行:

  1. 7
  2. 11
  3. 13

这是我的代码:

(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)不是函数名称; 尝试使用符号代替

任何想法如何使这段代码正常工作?

Rai*_*wig 5

请记住:宏转换代码.

如果你有像这样的代码

(do-primes (n 5 15)
 (fresh-line)
 (princ n))
Run Code Online (Sandbox Code Playgroud)

您应该问自己的第一个问题是:转换后的代码应该是什么样的?然后将实际运行的代码.

一旦你知道目标代码应该是什么样子,你就可以编写翻译.

Lisp有类似的宏:dolistdotimes.你可以检查他们的宏扩展.上面有几种方法可以实现.一种是为身体使用功能和闭合.通常,在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)

将被计算,返回值将是返回的代码.这样没有意义.括号不对语句进行分组,也没有迭代.