2015-09-04 2 views
3

Мне нужно реализовать функцию, которая создает список из аргументов, передаваемых функции.Неожиданный результат функции (рекурсия)

Вот мой код:

(defun lstbuilder (&rest args) 
    (if (eq (car args) NIL) 
     NIL 
     (cons (car args) 
      (lstbuilder (cdr args))))) 

Эта функция не работает правильно. Результаты:

(lstbuilder 'a 'b 'c 'd 'e) ;expected (a b c d e) 
(a (b c d e)) ;result 
+0

Любая причина, по которой вы не реализуете ее более простым способом '(defun lstbuilder (& rest args) args)' – PuercoPop

ответ

4

Вы должны использовать (apply #'lstbuilder (cdr args)) для того, чтобы «знак» содержимого списка в качестве аргументов вызова функции.

+0

Спасибо. Не могли бы вы рассказать мне, как вернуть этот список из этой функции? –

+0

«Входящий список для аргументов & rest - это уже выделенный список». На самом деле, это * не * обязательно свежераспределенный список. Значение аргумента & rest функции, вызванной с APPLY, может совместно использовать структуру с аргументом list APPLY. В частности, [HyperSpec для APPLY] (http://www.lispworks.com/documentation/HyperSpec/Body/f_apply.htm) говорит: –

+1

«Когда функция получает свои аргументы через & rest, это допустимо (но не обязательно) для реализации привязать параметр rest к объекту, который разделяет структуру с последним аргументом. Поскольку функция не может определить, была ли она вызвана с помощью apply, а также (если это так), последний аргумент, применяемый, был константой ** соответствующие программы не должны ни полагаться на структуру списка списка остатков, чтобы быть свежеиспеченными, либо не изменять эту структуру списка. ** « –

5

Стиль

  • Пожалуйста, используйте стандартный лисповское форматирование. Использование редактора поможет вам отступы Lisp-кода.

  • Не помещайте только скобки на линии. Это просто освобождает пространство без выгоды.

  • Более длинные имена получают - между словами: list-builder.

  • Не используйте car и cdr для операций с списком. Используйте first и rest.

  • Конец списка: endp.

Пример:

(defun list-builder (&rest args) 
    (if (endp args) 
     nil 
    (cons (first args) 
      (apply #'list-builder (rest args))))) 

Поскольку переменная args уже список, мы можем просто скопировать его:

(defun list-builder (&rest args) 
    (copy-list args)) 

Или мы можем просто повторно использовать функцию list, которая уже создает список его аргументов:

(setf (symbol-function 'list-builder) 
     #'list) 
+0

Незначительный nitpick, я думаю, что if отступом в соответствии с стилем elisp, но не общим lisp, с последующим большим отступом. – PuercoPop

+2

@PuercoPop: на самом деле это стиль отступа по умолчанию в LispWorks. –

+1

Я этого не знал. Интересно, почему, в elisp это происходит потому, что предложение else завернуто в внешний progn, так что это было оправданием – PuercoPop

Смежные вопросы