1

我是 lisp 的初学者,我需要有人逐步向我解释prog表单的工作原理。l1 的初始值是多少?无?

如果列表在第一级有偶数个元素,则问题输出 T,否则输出 nil。

(defun nr_par (l)
  (prog ((l1 l))
    ciclu
    (cond
      ((null l1) (return T))
      ((null (cdr l1)) (return NIL))
      ((null (cddr l1)) (return T))
      (T (setf l1 (cddr l1))
         (go ciclu)))))

在控制台上:

(nr_par '(1 2 3 4 5 6 7 8))

T
4

3 回答 3

6

该程序很简单,但不是非常惯用的 lisp(它是命令式的,而不是函数式的)。逐步进行如下。

prog使用一系列变量绑定,在这种情况下,最初l1被分配了值。l然后,循环开始的一系列语句(同样,不是非常 lisp 惯用的)。

这种类型的循环使用标签 ( ciclu) 和 goto 指令 ( go),同样不推荐,但它存在。之后,cond检查一系列案件。当列表为空 ( null) 时,返回 true,在其他情况下,检查长度是偶数还是奇数,然后返回值。

在列表长于一个或两个元素的情况下(这两种情况都不为空),l1列表被调整为指向其自身的下一个元素(cddr函数)的下一个。

最后,该go函数将程序转回ciclu标签。

cond满足任何子句时,程序将结束,返回TNIL

于 2013-01-13T14:36:45.527 回答
2

参见CLHS 中的 PROGL1varLinit-form,所以 的初始值L1是 的值L

于 2013-01-13T14:28:21.753 回答
1

正如CLHS 页面prog所说,它做了三件事:让您拥有本地变量并初始化它们;让你有标签tagbody和使用go; 并让您在命名中使用returnas :blockNIL

(defun nr_par (l)                     
  (prog ((l1 l))                           ; local binding(s)
    ciclu                             
    (if (null l1)       (return T))        ; return
    (if (null (cdr l1)) (return NIL)) 
    (setf l1 (cddr l1))  
    (go ciclu)))                           ; go

(defun nr_par1 (l)                         ; directly equivalent
  (labels ((ciclu (l1) 
             (if (null l1)       (return-from ciclu T)) 
             (if (null (cdr l1)) (return-from ciclu NIL)) 
             (ciclu (cddr l1))))
    (ciclu l)))

(defun nr_par2 (l)                         ; also equivalent
  (do ((l1 l (cddr l1)))
      (NIL)                                ; while T ...
    (cond
      ((null l1)       (return T))
      ((null (cdr l1)) (return NIL)))))

函数调用goto毕竟是一种美化,不是吗?

另请参阅Lisp中的最长递减序列,以获取将几个相互递归函数手动编译成prog带有一堆GO语句的示例。

于 2013-01-20T15:58:25.680 回答