以下代码旨在从指定的等待时间开始倒计时,然后评估提供的表单:
(defun wait (seconds form)
(let ((end (+ (get-universal-time) seconds)))
(do ()
((>= (get-universal-time) end)
(eval form))
(sleep 1))))
Run Code Online (Sandbox Code Playgroud)
如果我跑:
(wait 5 (format t "output"))
Run Code Online (Sandbox Code Playgroud)
结果是"输出"将在倒计时之前发送到stdout.输出"输出"后,程序仍像往常一样倒计时.
我得到了预期的结果,其中"输出"在倒计时完成后发送到stdout,具有以下代码:
(defun wait (seconds form)
(let ((end (+ (get-universal-time) seconds)))
(do ()
((>= (get-universal-time) end)
(format t "output"))
(sleep 1))))
Run Code Online (Sandbox Code Playgroud)
为什么在DO循环中调用EVAL会在声明DO循环时进行评估,但直接插入正在评估的表单会导致它等到结果时间?
Rai*_*wig 10
初学者的Lisp编程的第一定律:不,你不需要eval
.
您的函数没有获得表单(foo)
,而是评估结果(foo)
.在调用函数之前,将评估函数的所有参数.Lisp不会使用参数的形式调用函数,而是使用评估参数的结果.
你的代码
(wait ; function wait
5 ; argument expression 1
(format t "output")) ; argument expression 2
Run Code Online (Sandbox Code Playgroud)
怎么了?
wait
是一个功能,得到它.5
- >5
(format t "output")
- > NIL
+输出作为副作用wait
用参数5
和函数调用函数NIL
改进:传递功能
如果您不想在调用中运行参数,请创建一个函数(lambda () (foo))
,该函数将被计算为函数对象,将其传递给变量delayed-function
,然后调用它(funcall delayed-function)
.
这里发生了什么?
(wait
5
(lambda ()
(format t "output")))
Run Code Online (Sandbox Code Playgroud)
wait
是一个功能,得到它.5
- >5
(lambda () (format t "output"))
- >一个函数对象wait
使用参数5
和函数对象调用函数现在你的函数wait
需要做它想做的事情,并使用FUNCALL在正确的位置调用传递的函数对象.