从Scheme中的列表中删除元素

时间:2012-11-25 11:11:29

标签: list lisp scheme element removeall

这是我第一次发帖,我对计划有疑问。 我必须从列表中删除所有出现的元素,并将它们作为参数传递, 输入这样的参数时:

]=> (rmobject '(1 2 3 5 0 2 3 5 3) 3)

我收到了一个错误:

The object (3 5 3 2 3 6 3) is not applicable

我想这是因为第二个lambda,它不能正常工作,但为什么呢?

(define (rmobject list1 obj)
  (if (null? list1)
      '() 
       (if (= obj (car list1))
           ((lambda (list1) (cdr list1)) list1)
           ((lambda (list1) (list1)) list1)))
        (cons (car list1) (rmobject (cdr list1) obj)))

我重写了代码,这在删除元素时正常工作,但正确的没有,两者都假设相同。提前致谢

(define (rmobject list1 obj)
  (if (null? list1)
     '() 
  (if (= obj (car list1))
      (rmobject (cdr list1) obj)
      (cons (car list1) (rmobject (cdr list1) obj)))))

2 个答案:

答案 0 :(得分:2)

代码中的第一个版本没有多大意义。为什么以这种方式使用lambda?你应该递归地调用定义的相同过程,而不是创建一次性匿名过程,这对于解决手头的问题是行不通的。这一部分:(list1)导致错误The object is not applicable:你试图调用列表就好像它是一个过程 - 因为它被括号括起来。请记住,在Scheme中,这样的语法:(foo)表示要调用foo 过程

您的代码的第二个版本很好,这是实现remove-all过程的简单方法。但是,有点挑剔:当你发现自己嵌套if时,这是一个明确的信号,cond会更合适。另请注意,使用equal?代替=是个好主意,这样您的程序将不仅仅适用于数字:

(define (rmobject list1 obj)
  (cond ((null? list1)
         '())
        ((equal? obj (car list1))
         (rmobject (cdr list1) obj))
        (else
         (cons (car list1)
               (rmobject (cdr list1) obj)))))

供将来参考:您正在实施的程序通常作为翻译的一部分包含在内。例如,在Racket中我们有remove*,它使用equal?作为测试相等性的默认过程:

(define (rmobject list1 obj)
  (remove* (list obj) list1))

此外,您可以像@ Maxwell的回答一样使用filter。另一种写作方式:

(define (rmobject list1 obj)
  (filter (negate (curry equal? obj)) list1))

无论如何,这有效:

(rmobject '(1 2 3 5 0 2 3 5 3) 3)
=> '(1 2 5 0 2 5)

答案 1 :(得分:1)

问题是在行((lambda (list1) (list1)) list1)))中你组成了一个接受参数(list1)的函数,然后你尝试将其作为函数调用。因为该函数实际上是传递一个列表,所以解释器退出并出现错误。

正如您在第二次尝试中发现的那样,使用您提出的算法,通过lambda编写函数不是必需的,甚至是连贯的。即便如此,有许多技术比你在第二次尝试时使用的技术简单得多。我将演示一个实际上使用lambda的人,这样你就可以看到它是如何工作的。我所指的替代技术依赖于filter,其工作原理如下:

(define (rmobject list1 obj)
  (filter (lambda (x) (not (equal? x obj))) list1))