2017-02-14 2 views
3

Я новичок в распространении lisp, когда вижу в аргументе аргументов функции, я думал, что он похож на *args в ruby. И я начал писать функцию sumit, чтобы сделать то же самое, что и +.как бороться с `& rest` args в общем lisp

(defun sumit (&rest args) 
    (if (null args) 
     0 
     (+ (car args) (sumit (cdr args))))) 

но когда я призываю (sumit 1 2 3) он получает ошибку сегментации, рекурсии никогда не заканчивается. (sumit) работает.

Так что мой подозреваемый (null args) часть, но после изменения чего-то вроде (eql nil args) или что-то подобное не работает.

Так что же такое способ разложения &rest args? Каков правильный способ проверить nil?

+3

'SUMIT' принимает переменное число чисел в качестве аргументов, но в' (sumit (cdr args)) 'вы вызываете его одним аргументом списка, а не цифрами. Вам нужно использовать '(вместо этого применить # 'sumit (cdr args))'. – jkiiski

+0

@jkiiski ohhh, это правильно! спасибо! btw, есть ли способ расширить список на несколько аргументов без использования 'apply'? – delta

+0

@delta: no, use APPLY –

ответ

3

(sumit (cdr args)) вызывает sumit по одному аргументу - список. Вы должны использовать apply:

(defun sumit (&rest args) 
    (if args 
     (+ (car args) (apply #'sumit (cdr args))) 
     0)) 

Примечания:

  1. Эта реализация не является хвостовой рекурсией (в то время как ANSI CL делает не требуют оптимизации хвостового вызова, многие реализации сделать обеспечивают его) ,
  2. Взгляните на call-arguments-limit и lambda-parameters-limit.
  3. Суммируя элементы списка можно использовать (apply #'+ list-of-numbers), , но из-за указанных выше двух переменных, (reduce #'+ list-of-numbers) является гораздо более эффективным подходом.
+0

Что касается примечания 1, Common Lisp в любом случае не гарантирует хвостовую рекурсию. – acelent

+1

@acelent: спасибо, да, я знаю, см. Редактирование. – sds