在DO运行之前调用在DO的结果部分中评估的EVAL

时间:2016-01-24 06:20:03

标签: lisp common-lisp eval

以下代码旨在从指定的等待时间开始倒计时,然后评估提供的表单:

(defun wait (seconds form)
       (let ((end (+ (get-universal-time) seconds)))
         (do ()
          ((>= (get-universal-time) end)
           (eval form))
        (sleep 1))))

如果我跑:

(wait 5 (format t "output"))

结果是“输出”将在倒计时之前发送到stdout。输出“输出”后,程序仍像往常一样倒计时。

我得到了预期的结果,其中“输出”在倒计时结束后发送到stdout,使用以下代码:

(defun wait (seconds form)
       (let ((end (+ (get-universal-time) seconds)))
         (do ()
          ((>= (get-universal-time) end)
           (format t "output"))
        (sleep 1))))

为什么在DO循环中调用EVAL会在声明DO循环时进行评估,但直接插入正在评估的表单会导致它等到结果时间?

2 个答案:

答案 0 :(得分:10)

初学者的Lisp编程的第一定律:不,你不需要public function saveIngredients($ingredient_id) { foreach($ingredient_id as $row => $value) { $query=$this->db->where('ingredient_id', $value->ingredient_id); if($query->num_rows > 0) { echo '<div class="alert alert-error"><a class="close" data-dismiss="alert">×</a><strong>'; echo "Ingredient already taken"; echo '</strong></div>'; } else { $this->db->insert('ingredient', $value); $insert_id[] = $this->db->insert_id(); } } return $insert_id; }

您的函数未获取表单eval,而是评估(foo)的结果。在调用函数之前,将评估函数的所有参数。 Lisp不会使用参数的形式调用函数,而是调用参数的结果。

您的代码

(foo)

会发生什么?

  1. (wait ; function wait 5 ; argument expression 1 (format t "output")) ; argument expression 2 是一个函数,得到它。
  2. 评估wait - &gt; 5
  3. 评估5 - &gt; (format t "output") +输出作为副作用
  4. 使用参数NILwait
  5. 调用函数5

    改进:传递功能

    如果您不想在调用中运行参数,请创建一个函数NIL,该函数将被计算为函数对象,将其传递给变量(lambda () (foo)),并调用它delayed-function

    这里发生了什么?

    (funcall delayed-function)
    1. (wait 5 (lambda () (format t "output"))) 是一个函数,得到它。
    2. 评估wait - &gt; 5
    3. 评估5 - &gt;一个功能对象
    4. 使用参数(lambda () (format t "output"))和函数对象
    5. 调用函数wait

      现在你的函数5需要做它想做的事情,并使用FUNCALL在正确的位置调用传递的函数对象。

答案 1 :(得分:2)

调用函数时,其参数在传递给函数之前会被计算一次。如果要传递未评估的表单,可以使用宏。 E.g:

(defmacro wait (seconds form)
  (let ((end-name (gensym "end")))
    `(do ((,end-name (+ (get-universal-time) ,seconds)))
         ((>= (get-universal-time) ,end-name))
       ,form
       (sleep 1))))

查看其宏扩展:

CL-USER> (macroexpand-1 '(wait 10 (print 'test)))
(DO ((#:|end868| (+ (GET-UNIVERSAL-TIME) 10)))
    ((>= (GET-UNIVERSAL-TIME) #:|end868|))
  (PRINT 'TEST)
  (SLEEP 1))