Lisp是如何实现的;prog";在这个例子中工作?

Lisp是如何实现的;prog";在这个例子中工作?,lisp,common-lisp,Lisp,Common Lisp,我是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 (se

我是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

请参见:
L1
是var,
L
是init form,因此
L1
的初始值是
L
的值。请参见:
L1
是var,
L
是init form,因此
L1
的初始值是
L
的值。该程序很简单,但不是非常地道的lisp>
(这是非常必要的,而不是功能性的)

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

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

如果列表长度超过一个或两个元素(两种情况均不为空),则调整
l1
列表以指向其自身的下一个元素(函数
cddr

最后,
go
函数将程序返回到
ciclu
标记


当满足任何
cond
子句时,程序将完成,返回
T
NIL
程序很简单,但不是非常惯用的lisp(它是命令式的,而不是函数式的)

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

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

如果列表长度超过一个或两个元素(两种情况均不为空),则调整
l1
列表以指向其自身的下一个元素(函数
cddr

最后,
go
函数将程序返回到
ciclu
标记

当满足任何
cond
子句时,程序将完成,返回
T
NIL

,如上所述,它可以做三件事:让您拥有本地变量并初始化它们;让您拥有标签,如
tagbody
和使用
go
;让您在
块中使用
返回
de>命名为
NIL

(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
,不是吗

另请参见一个示例,该示例表示几个相互递归的函数,这些函数通过一组
GO
语句手工编译成
prog

如前所述,它可以做三件事:让您拥有本地变量并对其进行初始化;让您拥有标签,如
tagbody
中所示,并使用
GO
;以及让您使用
return
位于名为
NIL
块中:

(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
,不是吗


另请参见一个示例,该示例用一组
GO
语句将几个相互递归的函数手工编译成
prog

“不太惯用的lisp”-实际上,60年代和70年代的许多lisp代码都是这样的。今天的示例非常惯用,因为它包含在一种常见的lisp“练习”中(我总是假设要求像“使用PROG、COND、GO、CD[D]R等编写某某函数”。似乎世界上没有一位教师会接受
(evenp(length list))
作为解决方案。甚至
(reduce#'(lambda(v#)(而不是v))list:初始值t)
“不太惯用的lisp”-实际上这是60年代和70年代许多lisp代码的样子。今天的示例非常惯用,因为它包含在一种常见的lisp“练习”风格中(我总是假设要求类似于“使用PROG、COND、GO、CD[D]R等编写某个函数”。似乎世界上没有一位教师会接受
(evenp(length list))
作为解决方案。甚至
(reduce#'(lambda(v#)(not v))list:初始值t)