Common lisp 使用宏运行函数
我的任务是使用macrodo primes计算a和b之间所有primes的列表,然后使用自定义代码打印它们 说(素数(n 5 15)(换行)(princ n))应打印以下4行:Common lisp 使用宏运行函数,common-lisp,Common Lisp,我的任务是使用macrodo primes计算a和b之间所有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-fun
(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))
但是,当我运行代码时,出现以下错误:
EVAL:(FRESH-LINE)不是函数名;尝试改用符号
如何使此代码正常工作,有什么想法吗?宏可能非常棘手。这就是为什么在调试它们时,首先要做的是对它们进行宏扩展。(在Emacs中有一个快捷方式:
C-C RET
)您还可以在REPL中键入(macroexpand[此处的宏用法])
。在您的情况下,您应该键入:
(macroexpand '(do-primes (n 5 15) (fresh-line) (princ n)))
这将产生((新鲜线)(原理N))
由于
(换行)
不是函数名-换行
是函数名,因此会出现该错误。宏可能非常棘手。这就是为什么在调试它们时,首先要做的是对它们进行宏扩展。(在Emacs中有一个快捷方式:C-C RET
)您还可以在REPL中键入(macroexpand[此处的宏用法])
。在您的情况下,您应该键入:
(macroexpand '(do-primes (n 5 15) (fresh-line) (princ n)))
这将产生((新鲜线)(原理N))
由于
(换行)
不是函数名-换行
是函数名,因此会出现该错误。请记住:宏转换代码。
如果你有这样的代码
(do-primes (n 5 15)
(fresh-line)
(princ n))
您应该问自己的第一个问题是:转换后的代码应该是什么样子?然后实际运行的代码
一旦知道目标代码应该是什么样子,就可以编写翻译了
Lisp有类似的宏:dolist
和dotimes
。您可以检查它们的宏扩展。有几种方法可以实现上述功能。一种是对主体使用函数和闭包。通常情况下,在Lisp中,我希望它们能够扩展到一些低级代码中进行循环迭代
在伪代码表示法中,更高级的编码方法是:
for n from n below/upto 15
when is-prime (n)
do fresh-line () and princ (n)
因此,do primes
宏需要扩展为类似的代码-但Lisp代码。许多其他的方法也是可能的
您的代码
(defmacro do-primes ((var startv endv) &body body)
`(my-func ,startv ,endv)
`(,@body))
宏有两个子窗体。为什么?第一个表单被计算,然后返回到nowhere。结果将被垃圾收集,因为它未被使用
第二种形式
`(,@body)`
将进行计算,返回值将是返回的代码。这样说是没有道理的。括号不会对语句进行分组,也不会进行迭代。记住:宏转换代码。 如果你有这样的代码
(do-primes (n 5 15)
(fresh-line)
(princ n))
您应该问自己的第一个问题是:转换后的代码应该是什么样子?然后实际运行的代码
一旦知道目标代码应该是什么样子,就可以编写翻译了
Lisp有类似的宏:dolist
和dotimes
。您可以检查它们的宏扩展。有几种方法可以实现上述功能。一种是对主体使用函数和闭包。通常情况下,在Lisp中,我希望它们能够扩展到一些低级代码中进行循环迭代
在伪代码表示法中,更高级的编码方法是:
for n from n below/upto 15
when is-prime (n)
do fresh-line () and princ (n)
因此,do primes
宏需要扩展为类似的代码-但Lisp代码。许多其他的方法也是可能的
您的代码
(defmacro do-primes ((var startv endv) &body body)
`(my-func ,startv ,endv)
`(,@body))
宏有两个子窗体。为什么?第一个表单被计算,然后返回到nowhere。结果将被垃圾收集,因为它未被使用
第二种形式
`(,@body)`
将进行计算,返回值将是返回的代码。这样说是没有道理的。括号不会对语句进行分组,也没有迭代。您应该在此处检查示例:
我想,它会解释你所需要的一切。你应该在这里检查示例: 我想,它会解释你需要的一切