如何在LISP中不使用删除功能从列表中删除元素

时间:2014-04-14 13:29:44

标签: error-handling lisp

  (defun my_remove(e list1 list2)
  (if (null list1)
   nil
  ((setf x car(list1))
    (if (!= x e)
    ((my_append  e list2 )
    (setf y cdr(list1))
    (my_remove(e y list2)))

    ((setf y cdr(list1))
    (my_remove(e y list2))
     )))))

我正在尝试编写一个函数来从列表中删除一个元素,但是我收到一个错误“它应该是lambada函数”而且我不知道我的代码是正确还是错误。

1 个答案:

答案 0 :(得分:1)

代码问题

您的代码存在一些问题。首先,让我们用标准缩进来看待它

(defun my_remove(e list1 list2)
  (if (null list1)
      nil
      ((setf x car(list1))                   ; (i)
       (if (!= x e)
           ((my_append  e list2 )            ; (ii)
            (setf y cdr(list1))              ; (iii)
            (my_remove(e y list2)))          ; (iv)
           ((setf y cdr(list1))              ; (v)
            (my_remove(e y list2)))))))      ; (vi)

每个标记的行都有问题。 Lisp中函数调用的语法是

(function argument…)

这意味着在您的行(i)中,您尝试使用参数(setf x car(list1))调用名为(if (!= x e) …)的函数。当然,这不是一个函数的名称,我怀疑即使它是,你也不想用参数(if (!= x e) …)来调用它。同样

(setf x car (list1))

尝试将x设置为变量car的值(并且没有一个),然后为地点(list1)分配新值。由于函数调用的语法是(function argument…),因此您需要:

(setf x (car list1))

如果您尝试对表单进行排序,可以考虑使用cond,其中您可以提供多个表单,或progn(请参阅In Common Lisp, why do multi-expression bodies of (if) statements require (progn)?)。

例如,而不是

           ((my_append  e list2 )            ; (ii)
            (setf y cdr(list1))              ; (iii)
            (my_remove(e y list2)))          ; (iv)
你可能想要

           (progn
            (my_append  e list2 )            ; (ii)
            (setf y cdr(list1))              ; (iii)
            (my_remove(e y list2)))          ; (iv)

但是,你也会遇到一些问题。在(iii)(iv)中,您需要使用(cdr list1)(my_remove e y list2),如上所述,但您也遇到了正在评估的问题{{1}和(ii),但你丢弃了价值。

简化方法

如果您考虑(iii)的简单定义,我认为可能对您有利。通常,列表是空列表my-remove或cons列表,其列车是列表的第一个元素,其cdr是列表的其余部分。您可以使用这样的定义,然后:

  • 除去(X,列表)
    • 如果list为空,则返回列表(它为空,因此它当然不包含x)
    • 如果列表不为空,那么
      • 如果列表的第一个元素是x,则返回remove(x,rest(list))
      • 否则,列表的第一个元素不是x,所以返回一个新列表,其第一个元素是列表的第一个元素,其余部分是remove(x,rest(list))。

在代码中,它看起来像:

()
(defun my-remove (element list)
  (if (endp list)
      list
      (if (eql element (first list))
          (my-remove element (rest list))
          (list* (first list)
                 (my-remove element (rest list))))))

那些嵌套的CL-USER> (my-remove 1 '(1 2 3 1 2 3)) (2 3 2 3) 看起来有点难看,你可能想在这里使用if,即使你不需要它允许的多个表达式主体:

cond

由于没有正文,其测试形式的计算结果为true的(defun my-remove (element list) (cond ((endp list) list) ((eql element (first list)) (my-remove element (rest list))) (t (list* (first list) (my-remove element (rest list)))))) 子句返回测试表单的值,您甚至可以使最后一个子句更简单:

cond