LISP更好地了解多级列表

时间:2018-10-28 17:35:19

标签: lisp common-lisp

我试图通过使函数删除多级列表中所有不是数字的元素来更好地理解lisp中的多级列表。我首先尝试使用striv0函数将其展平,然后检查列表的第一个参数是否为数字。但是尝试功能时遇到问题
(功能'(5(5 2(8)(7(9)5)))) 。我得到:COND:变量,如果没有值

代码:

    (DEFUN striv0 (lis)
(COND        ((NULL lis) NIL)
    ((ATOM lis) (LIST lis))
    (T (APPEND (striv0 (FIRST lis))
            (striv0 (REST lis))))
))

(DEFUN func (lis) 
(LET( (newList (striv0 lis))  ))
(COND ((NULL newList) NIL)
    ( T(IF (NUMBERP (FIRST newList))   
             ((func(REST newList)))))))

我相信我已经通过将第二个函数成型为第一个函数来解决问题,方法是检查数字参数或内部列表(如果它们都不是一个,则沿列表进一步移动)。

    (DEFUN  checkNumber (lis)
(COND    ((NULL lis) NIL)
    ((ATOM lis) (LIST lis))
    (T (if ( or(NUMBERP ( FIRST lis))(LISTP (FIRST lis)))
         (APPEND ( checkNumber (FIRST lis))
            ( checkNumber (REST lis)))
       ( checkNumber (REST lis))  )
     )   
)
)

2 个答案:

答案 0 :(得分:5)

以下是逐行反馈和一些提示:

(DEFUN func (lis)                    ; why is this called FUNC
                                     ;   and not something useful?
                                     ; why is the variable called
                                     ;  LIS and not LIST?

(LET( (newList (striv0 lis))  ))     ; why is this not indented?
                                     ; why does LET not have
                                     ;   body forms?
                                     ; why is the LET ending here?


(COND ((NULL newList) NIL)           ; why is this not indented?
    ( T(IF (NUMBERP (FIRST newList)) ; why is this not indented?
             ((func(REST newList)))))))  ; why are there so
                                         ;   many parentheses?
                                         ; why is it starting
                                         ;   with two parentheses?

答案 1 :(得分:4)

首先,格式化您的代码。公认的惯例是使用小写字母符号,并在符号名称中使用破折号e分隔单词部分。 G。 new-list。缩进用于在同一文本列上对齐同一级别的表单。 Lisp风格有很多文字,here是其中之一。这就是您的代码的外观:

(defun striv0 (lis)
  (cond ((null lis) nil)
        ((atom lis) (list lis))
        (t (append (striv0 (first lis))
                   (striv0 (rest lis))))))

(defun func (lis) 
  (let ((new-list (striv0 lis))))
  (cond ((null new-list) nil)
        (t (if (numberp (first new-list))
               (cons (first new-list) (func (rest new-list)))))))

好的编辑会为您完成缩进。如果缩进不符合您的期望,则说明您犯了语法错误。编辑器还将显示匹配的括号对。

Let的第一个参数是绑定列表,然后是 body 中的任意形式。绑定仅在该主体内有效。您想将cond表单放入该正文:

(defun func (lis) 
  (let ((new-list (striv0 lis)))
    (cond ((null new-list) nil)
          (t (if (numberp (first new-list))
                 ((func (rest new-list))))))))

请注意缩进如何自动反映代码结构:cond表单现在缩进了两个空格,以表明它位于let主体内。我实际编辑的是将let格式的右括号移到末尾。

那里的最后一个格式((func (rest new-list)))不是有效的Lisp格式。表单必须始终以运算符开头(可以是符号形式也可以是lambda形式)。我认为您在早期版本的问题中(cons (first new-list) (func (rest new-list)))看似正确。

我现在将尝试为这些功能找到更好的名称。您的striv0通常可以命名为flatten。在Lisp中,“多级列表”通常称为“树”。您的func可能因此称为keep-numbers-from-tree

我不确定拼合是否属于您的要求。无论如何,我都将其分开,因为每次通过递归再次执行此操作似乎都是多余的。首先展平,然后过滤数字。

如果拼合不属于您的要求,请不要这样做。遍历树时,每个点只有三种可能性:它是一个列表(然后递归),它是一个数字(保持)或它是一个非数字原子(跳过)。