宏和变量的常见 LIsp 问题

时间:2021-04-18 00:50:16

标签: lisp common-lisp

我有一个作业,需要使用 lisp 编写脚本。我在传递变量时遇到问题

这是代码。需要关注的问题:

(defmacro while (test &rest bodies)
   `(do ()
        ((not ,test))
        ,@ bodies)
) 
(defmacro += (var inc)
    `(print (eval var))
    ;(setf (eval var) (+ (eval var) inc))
)

(defmacro iterate (i begin end inc &rest others)
    (setf i begin)
    
    (while (<= i (eval end))
        ;(dolist (item others)
        ;    (eval item)
        ;)
       
        (print (list 'two i (eval end)))
        (+= (eval end) 1)
        (setf i (+ i inc))
    )
)

(setf n 5)
(iterate i 1 n 1
    (print (list 'one i))
    (+= n 1)
)

第一个问题在于将语句传递给迭代宏。当我尝试运行注释掉的 dolist 时,print 语句会在涉及变量 i 时抛出错误。出于某种原因,我无法使用具有值的宏变量 i 打印它,但它似乎想要默认为尚未设置的全局变量 i。我收到错误:

- EVAL: variable I has no value

第二个问题是当我调用“+=”宏时。迭代宏中的 end 值是 5,它是通过使用变量 N 传递给宏的,该变量 N 设置为 5,但是,当我使用“(+= (eval结束)1)”我无法让它传递值。我尝试删除“(+= (eval end) 1)”行中的 eval,当我尝试在“+=”宏中使用“(print (eval var))”打印它时,出现错误 - EVAL: 变量 END 没有值

我将如何解决这些问题?

1 个答案:

答案 0 :(得分:2)

你的第一个宏基本上是正确的。它生成代码。

(defmacro while (test &body body)
  `(do ()
       ((not ,test))
     ,@body))

我们可以通过一个例子来检查它。我们使用示例代码扩展宏。函数 MACROEXPAND-1 只扩展顶级宏一次。您需要将代码传递给函数 MACROEXPAND-1:

CL-USER 1 > (macroexpand-1 '(while (< i 10)
                              (print i)
                              (incf i)))
(DO NIL               ; NIL is the same as ()
    ((NOT (< I 10)))
  (PRINT I)
  (INCF I))
T
 

生成的代码是一个 DO 循环。就像预期的那样。

因此我们可以使用您的宏:

CL-USER 2 > (let ((i 5))
              (while (< i 10)
                (print i)
                (incf i)))

5 
6 
7 
8 
9 
NIL

你的其他宏应该是这样

  • 他们应该生成代码
  • 示例的宏展开应该显示正确的生成代码
  • 生成的代码应该可以工作

您的宏不应该

  • 正在使用 EVAL
  • 尝试计算代码以外的结果