Написание тестовой функции, использующей два пространства имен в 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))
который не уважает этот синтаксис. Если вы хотите определить переменную, которая содержит функцию, полученную в результате объединения двух функций, у вас есть несколько возможностей:
Используйте специальную переменную:
(defvar test (comp #'car #'cdr))
Используйте локальную переменную внутри формы:
(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)