Написание тестовой функции, использующей два пространства имен в lisp - PullRequest
1 голос
/ 19 июня 2019

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

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

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

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

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

Тот же код, переписанный в Lisp

(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)) вслушатель, я получаю

Не символ (FUNCTION CAR), используемый в качестве имени переменной в функции TEST.

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

Ответы [ 4 ]

6 голосов
/ 19 июня 2019

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))
5 голосов
/ 19 июня 2019
(defun test (comp #'car #'cdr))

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

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

Вы можете сделать:

(setf (symbol-function 'test)
      (comp #'car #'cdr))
1 голос
/ 19 июня 2019

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

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
0 голосов
/ 19 июня 2019

Другое предложение:

(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)
...