LINUX.ORG.RU

[wtf] onlisp

 


0

0

понадобилось тут заиплементить один хитрый макрос, и вспомнил я, что в главе classic macros onlisp'a было что-то похожее. в теле искомого макроса использовалась ф-я mappend, которая, как оказалось, была введена автором в начале книги.

ф-я выглядит так:
(defun mappend (fn &rest lsts)
(apply #’append (apply #’mapcar fn lsts)))

описание:
mappend offers a nondestructive alternative to mapcan.

т.е. это не деструктивная альтернатива mapcan'y.
а это явный wtf, ибо from lisp hypespec:
----
mapcan and mapcon are like mapcar and maplist respectively, except that the results of applying function are combined into a list by the use of nconc rather than list. That is,

(mapcon f x1 ... xn)
(apply #'nconc (maplist f x1 ... xn))

and similarly for the relationship between mapcan and mapcar.
-----

т.е. mappend == macpcar.

вопрос: может где-то я не прав, и здесь имеет место быть некий хитрый подвох? =)


s/mappend == macpcar/mappend == mapcar. /

asgard
() автор топика
Ответ на: комментарий от mo3r

> так ведь nconc-то имеет Side Effects: The lists are modified rather than copied.

уже нашёл косяк в своём предположении, соль не в том, что вы написали. mappend по задумке автора, суть mapcan without side-effects, т.е.

mapcan == (apply #'nconc (mapcar f x1 ... xn)) mappend == (apply #'append (mapcar f x1 ... xn)) я предположил, что mapcar == mappend, но это справедливо тогда и только тогда, когда list передаваемый mapcar'y имеет не имеет саблистов.

всё, пойду просплюсь.

asgard
() автор топика
Ответ на: комментарий от asgard

>но это справедливо тогда и только тогда, когда list передаваемый mapcar'y имеет не имеет саблистов.
Чего-то я этого не догнал. nconc (в отличие от append) порушит списки, которые возвращает f, изначальные списки (аргументы mapcan или mappend) не может порушить никто, они никаму не передаются. Сама функция f может порушить элементы этих списков, если они mutable, но это не зависит от того, что мы используем. То есть, насколько я понимаю, разница между ними будет только в том случае, если функция куда-то сохраняет списки перед тем как их вернуть.

Например:

(defvar *x*)

функция, циклически прокручивает список вправо на 1, и добавляет возвращаемый результат к списку *x*:

(defun ror (&rest x)
	   (if (<= (length x) 1) 
	       (progn
		 (push x *x*)
		 x)		      
	       (let ((y))
		 (setf y (last x 2))
		 (setf x (cons (cadr y) x))
		 (setf (cdr y) nil)
		 (push x *x*)
		 x)))

(setf *x* nil)
(setq l1 '(1 2 3))
(setq l2 '(10 20 30))
(setq l3 '(100 200 300))

(mappend #'ror l1 l2 l3) ==> (100 1 10 200 2 20 300 3 30)
*x* ==> ((300 3 30) (200 2 20) (100 1 10))
То есть, сохраненные функцией возврященные значения не пострадали

(setf *x* nil)
(mapcan #'ror l1 l2 l3) ==> (100 1 10 200 2 20 300 3 30) - без изменений, но:
*x* ==> ((300 3 30) (200 2 20 300 3 30) (100 1 10 200 2 20 300 3 30))
- лажа

ratatosk
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.