2012-12-01 3 views
1

Я изучаю накопление и складку, но что-то в моем коде неверно. Я хотел бы сравнить элементы во всем списке, но foldr использовать только первый и второй элементы. Вот мой код: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 -> (если < ...> #t #f)?

+0

Да, это лучше использовать 'предварительно' непосредственно, обратите внимание, что 'if' заканчивается возвращением так же, как' предварительно ' –

ответ

2

Эта проблема может быть решена намного проще с apply, используя тот факт, что операторы сравнения получают переменное число аргументов:

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

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

UPDATE

Для этой задачи, в частности, foldr не является правильным инструментом для работы (хотя это не невозможно, так как у вас есть demonstrated) - нет значения, которое нужно «накапливать», пока перебирается список, список либо упорядочен, либо нет для данного предиката ,

Из комментариев я понимаю, что процедура pre? может быть произвольной lambda, которая получает ровно два параметра.

Возможным решением было бы создать al-список всех пар последовательных элементов и проверить, верно ли предикат для всех из них. Обратите внимание, что последний элемент не будет иметь соответствующую пару, поэтому нам нужно исключить его из списка пар. Для этого я буду определять специальную 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 
+0

Я знаю о применении. Проблема в том, что она не работает с этим: (accum? '(1 3 4) (lambda (a b) (= a (- b 1)))), поскольку предикат не является стандартным. Это может быть какое-то лямбда-выражение. – Ats

+0

@Ats 'apply' может работать с любой процедурой, если передано правильное количество параметров. Код в моем ответе работает, потому что для операторов сравнения «правильное количество параметров» - это что-то большее или равное нулю. С другой стороны, и я собирался обновить свой ответ, вы не найдете прямой способ решить эту проблему с помощью 'foldr', это не лучший инструмент для работы. –

+0

@Ats Я обновил свой ответ –

0

Используется только первый и второй элементы, потому что вы явно используете (car list1) и (cadr list1), которые получают первый и второй элементы.

Обратите внимание, что когда вы на самом деле не используете x и y, аргументы передаются лямбда. Это верный признак того, что вы делаете что-то неправильно.

PS: Это не связано с вашей проблемой, но написание (if condition #t #f) в значительной степени аналогично тому, как писать condition. Так что да, оставляя if лучше, так как это нецелесообразно.

+0

я вижу, (предварительно ? xy). Но теперь эта проблема: <: ожидает тип как второй аргумент, данный: #t; другими аргументами были: 4. – Ats

+0

@Ats Да, это потому, что так, как вы его написали, второй аргумент в 'lambda' будет логическим, но' <'ожидает два числа в качестве аргументов. Я не уверен, что вы хотите использовать 'foldr' для этого вообще. И если вы это сделаете, вам нужно передать больше, чем просто булевое, как аккумулятор. – sepp2k

+0

Мне нужно использовать foldr.Я пытаюсь проверить пустой список для последнего аргумента, но я не знаю, как это сделать. – Ats