Есть 2 функции, первая без сайд-эффектов генерирует новый список, вторая — деструктивно меняет значение одного из своих аргументов:
(defun f (a)
(mapcar #'1+ a))
(defun f2 (a b)
(map-into b #'1+ a))
Вторая функция, насколько я понимаю, должна быть и быстрей и меньше использовать память, за счет того, не происходит дополнительного выделения памяти при каждом вызове.
Но тестовые запуски показывают обратное — мало того, что f2 работает почти на 2 порядка медленней, так еще и памяти. как будто, больше потребляет:
CL-USER> (let ((xs (make-list 1000 :initial-element 0)))
(time
(dotimes (i 100)
(reduce #'+ (f xs)))))
Evaluation took:
0.01 seconds of real time
0.008999 seconds of user run time
0.0 seconds of system run time
0 calls to %EVAL
0 page faults and
2,399,464 bytes consed.
NIL
CL-USER> (let ((xs (make-list 1000 :initial-element 0)))
(let ((ys (make-list 1000)))
(time
(dotimes (i 100)
(reduce #'+ (f2 xs ys))))))
Evaluation took:
0.647 seconds of real time
0.646902 seconds of user run time
0.0 seconds of system run time
0 calls to %EVAL
0 page faults and
3,202,280 bytes consed.
При использовании вектора вместо списка разница в скорости уменьшается до 2 раз: с использованием f — 0.012, с f2 — 0.022.
И я не могу понять, чем объясняется большая скорость функции f? И прав ли я, что функция f по логике должна больше выделять памяти?
И может быть, кого-нибудь не затруднит попробовать такой тест на haskell'е?