1

我正在学习积累和折叠,但我的代码中有问题。我想比较所有列表中的元素,但 foldr 只使用第一个和第二个元素。这是我的代码:

(define accum?
  (lambda (list1 pre?)
  (foldr (lambda (x y) 
               (if (pre? (car list1) (cadr list1)) #t #f))
         #f
         list1)))

(accum? '(1 2 3 4) <) --> #t
(accum? '(3 2 3 4) <) --> #f
(accum? '(1 2 5 4) <) --> #t (should be #f)
(accum? '(5 7 2 3) <) --> #t (should be #f)

你知道哪里错了吗?顺便说一句,最好只使用 (pre? (car list1) (cadr list1)) 而不使用 if --> (if <...> #t #f)?

4

2 回答 2

2

apply使用比较运算符接收可变数量的参数这一事实可以更轻松地解决此问题:

(apply < '(1 2 3 4))
=> #t

(apply < '(1 2 5 4))
=> #f

更新

特别是对于这个问题,foldr它不是适合这项工作的工具(尽管这并非不可能,正如您所展示的那样) - 在遍历列表时没有要“累积”的值,列表要么是有序的或者不是给定的谓词。

从评论中,我了解到该pre?过程可以是任意的lambda,只接收两个参数。

一个可能的解决方案是创建所有连续元素对的所有列表,并检查谓词是否对所有元素都成立。请注意,最后一个元素没有对应的对,因此我们需要将其从对列表中排除。为此,我将定义一个特殊的zip过程,给定两个输入列表,它负责创建一个对列表,同时考虑到列表可以具有不同长度的事实:

(define (zip lst1 lst2)
  (if (or (null? lst1) (null? lst2))
      '()
      (cons (list (car lst1) (car lst2))
            (zip (cdr lst1) (cdr lst2)))))

(zip '(1 2 3) '(2 3))
=> '((1 2) (2 3))

现在放在一起,我们可以像这样解决原来的问题:

(define (accum? lst pre?)
  (andmap (lambda (tuple)
            (pre? (car tuple) (cadr tuple)))
          (zip lst (cdr lst))))

请记住,它不适用于空列表,但为此添加特殊情况很简单。现在可以任意进行比较lambdas

(accum? '(1 2 3) (lambda (a b) (= a (- b 1))))
=> #t
于 2012-12-01T18:03:35.390 回答
0

它只使用第一个和第二个元素,因为您明确使用(car list1)and (cadr list1),它得到了第一个和第二个元素。

请注意,当您实际上不使用xandy时,传递给 lambda 的参数。这是一个明确的迹象,你做错了什么。

PS:这与您的问题无关,但是写作与写作(if condition #t #f)几乎是一回事condition。所以,是的,省略它if会更好,因为它没有任何意义。

于 2012-12-01T16:44:08.220 回答