Приложение, а не процедура (процедура сопоставления схемы)

Я пытаюсь написать свою собственную упрощенную процедуру карты в R5RS. Короче говоря, он принимает процедуру и два списка и возвращает список с результатами процедуры, вызванной для каждой пары объектов в двух списках аргументов, пока ни один из них не станет пустым.

Это прекрасно работает для арифметических операторов, таких как:

(map2-rec + '(1 2 3) '(1 2 3 4))

Однако, когда я пытаюсь передать анонимную лямбда-функцию (возвращаемое значение моей процедуры Both?), которая возвращает либо #t, либо #f, это не работает.

(define (map2-rec proc items1 items2)
  (if (or (null? items1) (null? items2))
      '()
      (cons (proc (car items1) (car items2))
            (map2-rec proc (cdr items1) (cdr items2)))))


(define (both? proc)
  (lambda (item1 item2)
    ((if (and (proc item1) (proc item2))
         #t
         #f))))

Конкретная ошибка, которую я получаю в DrRacket:

application: not a procedure;  
expected a procedure that can be
applied to arguments   
given: #t   
arguments...: [none]

Если бы кто-нибудь мог сказать мне, как я могу исправить эту ошибку, я был бы очень рад. Я не могу понять, почему этот код не работает сам.


person Henrik Hillestad Løvold    schedule 18.02.2014    source источник
comment
возможный дубликат application: не процедура в двоичных арифметических процедурах Эта проблема обычно возникает, когда у вас есть дополнительный набор скобок (в данном случае это ((if … #t #f)), так что результат (if … #t #f) (в данном случае #t) вызывается как процедура (но это не процедура).   -  person Joshua Taylor    schedule 18.02.2014
comment
Кроме того, (and … …) уже возвращает логическое значение; (if test #t #f) эквивалентно test. Вы должны использовать (define (both? proc) (lambda (item1 item2) (and (proc item1) (proc item2)))).   -  person Joshua Taylor    schedule 18.02.2014
comment
@JoshuaTaylor and не обязательно возвращает логическое значение (например: (and 1 2)) - хотя он отлично работает с примером OP, но если по какой-то причине both? должен возвращать исключительно #t или #f, можно использовать if   -  person Óscar López    schedule 18.02.2014
comment
@ÓscarLópez Хороший вопрос! Да, если OP Henrik определенно нужен #t или #f, то (if … #t #f) - это то, что нужно. Кажется, я припоминаю, что большинство схем были немного строже в отношении того, что все, что не является ложным (#f в Scheme и () во многих других Лиспах), является истинным, поэтому я склонен ожидать только, что and возвращает ложь или значение поведения последнего аргумента в Общий Лисп.   -  person Joshua Taylor    schedule 18.02.2014


Ответы (1)


В both? есть лишняя (и ошибочная) пара скобок, окружающих выражение if. Это должно исправить это:

(define (both? proc)
  (lambda (item1 item2)
    (if (and (proc item1) (proc item2))
        #t
        #f)))

Теперь ваша процедура работает так, как ожидалось:

(map2-rec + '(1 2 3) '(1 2 3 4))
=> '(2 4 6)
(map2-rec (both? even?) '(1 2 3) '(1 2 3 4))
=> '(#f #t #f)
person Óscar López    schedule 18.02.2014
comment
Вау, вот оно! Большое спасибо. Я приму ответ, как только таймер будет готов :) - person Henrik Hillestad Løvold; 18.02.2014
comment
@HenrikHilstadLøvold без проблем, мне было очень приятно :) - person Óscar López; 18.02.2014
comment
Ответ @ Хенрика Оскара, конечно, правильный, но вы можете (и должны) вообще отказаться от if и просто вернуть (and (proc item1) (proc item2)) напрямую. - person Chris Jester-Young; 18.02.2014