Написание тестовой функции, использующей два пространства имен в lisp

Я начал изучать Lisp и использовать Lispworks personal edition 6.1.1 и столкнулся с проблемой при оценке основных функций. Я могу понять их правильно в Схеме, но они не работают, когда я пытаюсь оценить их в Лиспе.

В Лиспе я знаю, что у каждого символа есть два пространства имен. Поэтому я попытался написать простую процедуру для составления двух процедур. Он отлично работает в Scheme, но в Lisp есть проблема с оценкой.

Код в схеме работает отлично и возвращаю 2

(define (comp a b)
  (lambda (x)
    (a (b x))))

(define test (comp car cdr))
(test '(1 2 3))

Тот же код переписан в Лиспе

(defun comp (a b)
  (lambda (x)
    (funcall a (funcall b x))))

(defun test (comp #'car #'cdr))

(funcall test '(1 2 3))

Ошибка в lispworks:

Пытаясь связать не-символ, (FUNCTION CAR),

поэтому, когда я пытаюсь оценить (defun test (comp #'car #'cdr)) в слушателе я получаю

Non-символ (FUNCTION CAR) используется как имя переменной в функции TEST,

Я не понимаю, почему не работает так написано. Я бы оценил любую помощь

4 ответа

Решение

defun используется для определения функции с параметрами:

defun function-name lambda-list [[declaration* | documentation]] form*

поэтому он требует лямбда-списка после имени функции, но вы написали:

(defun test (comp #'car #'cdr))

который не уважает этот синтаксис. Если вы хотите определить переменную, которая содержит функцию, полученную в результате объединения двух функций, у вас есть несколько возможностей:

  1. Используйте специальную переменную:

    (defvar test (comp #'car #'cdr))
    
  2. Используйте локальную переменную внутри формы:

    (let ((test (comp #'car #'cdr)))
      (funcall test '(1 2 3))
    

Вы даже можете назначить его глобальному имени функции, например:

(setf (symbol-function 'test) (comp #'car #'cdr)

и в этом случае вы можете использовать имя как обычное имя функции, без funcall:

(test '(1 2 3))
(defun test (comp #'car #'cdr))

DEFUN ожидает лямбда-список после имени, и здесь ваш лямбда-список искажен, так как #'car не символ, но читается как (function car),

Что вы, вероятно, хотели сделать, это определить функцию test как состав car а также cdr; (comp ...) вернет соответствующий объект функции, но defun не позволяет иметь значение вместо лямбда-списка.

Вы могли бы сделать:

(setf (symbol-function 'test)
      (comp #'car #'cdr))

С локальными функциями:

CL-USER 1 > (flet ((comp (a b)
                     (lambda (x)
                       (funcall a (funcall b x)))))
              (let ((test (comp #'car #'cdr)))
                (flet ((test (x)
                         (funcall test x)))
                  (test '(1 2 3)))))
2

CL-USER 2 > (labels ((comp (a b)
                       (lambda (x)
                         (funcall a (funcall b x))))
                     (test (x)
                       (funcall (comp #'car #'cdr) x)))
              (test '(1 2 3)))
2

Еще одно предложение:

(defun comp (a b)
  (lambda (x)
     (funcall a (funcall b x))))

(defun mytest (x &key test)  ;; a "test" key is common
   (funcall test x))

(mytest '(1 2 3) :test (comp #'car #'cdr))

или же

(defun comp (x a b)
  (funcall a (funcall b x)))

(defun test (x a b)
  (comp x a b))

(test '(1 2 3) #'car #'cdr)
Другие вопросы по тегам