← Архив: Common Lisp

Добавить число к каждому элементу списка

Author: · 03.11.2011 21:24
· original author: vlitomsk
Из двухтомника Э.Хювёнена и И.Сеппянена."Определите функцию ДОБАВЬ, прибавляющую к элементам списка данное число"
Я определил функцию получния i-ого элемента списка, а потом конструирую новый, разбирая его по атомам с помощью новой функции и прибавляя к каждому данное число.
Вот что получилось:
(defun get-elem (x num)
   (do ()
      ((= num 0) (car x))
      (setq x (cdr x))
      (setq num (- num 1))
)
)

(defun dobav (x addition)
   (do ((i 1 (+ i 1)) (result (+ (get-elem x 0) addition)))
       ((= i (length x)) result)
       (setq result (cons result (+ addition (get-elem x i))))
)
)

Но мерзопакость этого способа в том, что он не распатронивает result и туда в конец вставляет новый элемент, а склеивает списки, из-за этого получаются СКОБОЧКИСКОБОЧКИСКОБОЧКИ:
(dobav '(1 35 12 64) 2) // перейдет в -> (((3 . 37) . 14) . 66)
Помогите пожалуйста разобраться , где я перемудрил.
Спасибо.
· original author: vlitomsk
P.S. знание пока только на уровне элементарных символов.
· original author: juna
>Помогите пожалуйста разобраться , где я перемудрил.
Да собственно везде. Достаточно
(defun dobav (L a) (cond ((null L) nil) (t (cons (+ a (car L)) (dobav (cdr L) a)))))
· original author: LinkFly
(defun addx (ls x)
    (do ((curls ls (cdr curls))
            res)
        ((null curls) (nreverse res))
      (setf res (cons (+ x
                                  (first curls))
                             res))))
(addx '(1 2 3) 10)
=> (11 12 13)
Но лучше так:
(defun addx (ls x)
    (mapcar (lambda (elt)
                     (+ elt x))
                  ls))
А ещё лучше так:
(defun addx (ls x)
    (loop :for elt :in ls
       :collect (+ x elt)))
· original author: LinkFly
Или так=) Тем более если в качестве учебного примера. А вообще, рекурсия в данной ситуации будет медленнее.
· original author: vlitomsk
Спасибо всем!Прохавал наконец-то, как решить это :)
· original author: vlitomsk
Немного не по теме, но может знает кто-нибудь.Есть какой-нибудь лисповый или не очень набор упражнений-пятиминуток на рекурсию? Чтобы потренироваться?
· original author: joba
Ну, не сильно медленнее (почти одинаково), на самом деле, если поддерживается tail recursion modulo cons.
· original author: joba
Попробуй почитать SICP. Там полно всяких задачек.
· original author: LinkFly
Так в "Мир Лиспа" как раз же.
· original author: LinkFly
Насчёт оптимизации хвостовой рекурсии то понятно. А что такое "modulo cons"?
Ну тут такое дело: как известно в CL это не стандартизировано. По факту sbcl вроде бы применяет. Но с другими реализациями могут быть неожиданные сюрпризы.
· original author: joba
>А что такое "modulo cons"?
http://en.wikipedia.org/wiki/Tail_call#Tail_recursion_modulo_cons
· original author: power
vitomsk, ты омич? У меня есть SICP бумажный на русском.
· original author: vlitomsk
SICP уже у меня появился и активно читается :)Спасибо!