Подскажите, пожалйста, как заставить aref сжевать вместо отдельных индексов их список, и при этом иметь возможность сделать setf на результат.
Вот так:
CL-USER>
(defvar *a* (make-array '(5 5 5)))
*A*
CL-USER> *a*
#3A
(((0 0 0 0 0) (0 0 0 0 0) (0 0 0 0 0) (0 0 0 0 0) (0 0 0 0 0))
((0 0 0 0 0) (0 0 0 0 0) (0 0 0 0 0) (0 0 0 0 0) (0 0 0 0 0))
((0 0 0 0 0) (0 0 0 0 0) (0 0 0 0 0) (0 0 0 0 0) (0 0 0 0 0))
((0 0 0 0 0) (0 0 0 0 0) (0 0 0 0 0) (0 0 0 0 0) (0 0 0 0 0))
((0 0 0 0 0) (0 0 0 0 0) (0 0 0 0 0) (0 0 0 0 0) (0 0 0 0 0)))
CL-USER>
(setf (apply #'aref *a* (list 1 2 3)) :test)
:TEST
CL-USER> *a*
#3A
(((0 0 0 0 0) (0 0 0 0 0) (0 0 0 0 0) (0 0 0 0 0) (0 0 0 0 0))
((0 0 0 0 0) (0 0 0 0 0) (0 0 0 :TEST 0) (0 0 0 0 0) (0 0 0 0 0))
((0 0 0 0 0) (0 0 0 0 0) (0 0 0 0 0) (0 0 0 0 0) (0 0 0 0 0))
((0 0 0 0 0) (0 0 0 0 0) (0 0 0 0 0) (0 0 0 0 0) (0 0 0 0 0))
((0 0 0 0 0) (0 0 0 0 0) (0 0 0 0 0) (0 0 0 0 0) (0 0 0 0 0)))
CL-USER>
Для архимага: это может потребоваться если у тебя размерность массива известна только в рантайме. ИМХО неплохой пример гибкости CL.
Насколько я понял, вопрос то был о другом.
Вы хотите расширить функциональность aref?
Тогда надо будет сделать shadow символа aref и написать одноименный макрос.
Но я бы не советовал так делать. Во всяком случае предварительно нужно все взвесить.
Не надо извращаться, сделайте свой макрос и и используйте defsetf и иже с ним. Если всё-таки очень надо, то - shadow на aref.
Спасибо. Я пробовал использовать funcall, но setf на него неадекватно реагирует.
2archimag
А о чем еще мог быть вопрос? Просто интересно.
> А о чем еще мог быть вопрос? Э.. Ну как бы буквально:
как заставить aref сжевать вместо отдельных индексов их список,
Понятно.
Кстати, а разве setf может работать с макросами? Да и написать такой макрос над aref у меня все равно не получилось, ведь список есть только в рантайме.
А shadow - это ж, наверное, значит полностью переписать aref, а если с нуля, так он небось сложный, а исходники искать долго и непонятно как.
И последний вопрос, правильно я понимаю, что &rest параметры - это только синтаксический сахар, а с точки зрения программирования они бесполезны и вредны. Всегда ведь легче сконструировать список в рантайм чем раскрыть его во внутренний (мне кажется, что это невозможно без применения funcall, apply и eval). Поэтому, по-моему, желательно, чтоб все функции имели без-&rest аналога, над которым бы уже строился макрос "для ежедневного пользования". Хотя, может быть, это просто у меня такое косное мышление, что я не могу эту задачу в обратную сторону решить.
Зачем с нуля переписывать? Он доступен через Common-lisp:aref
> И последний вопрос, правильно я понимаю, что &rest параметры - это
только синтаксический сахар, а с точки зрения программирования они
бесполезны и вредны.
Нет, с чего бы? rest-параметры избавляют от лишнего нагромождения скобок, где они не нужны.
Единственный минус &rest - rest-параметры вовнутрь функции передаются в виде списка, что приводит к лишнему мусору. Но это решается декларацией dynamic-extent, как сделано, например, в том же aref.
> Я пробовал использовать funcall, но setf на него неадекватно реагирует.
Да, setf не разбирает "по особому" funcall, т. к. использование (setf (funcall something ...) ...) бессмыслено, ибо в случае если something - это константное выражение (function xxx), то это эквивалентно (setf (xxx ...) ...), если же это выражение не константное - то setf не может определить в компайл-тайме каким образом он должен выполнять требуемое действие.
А apply чем в этом отношении лучше?
apply это тот же funcall только вид сбоку)) Просто аргументы apply передаются в виде списка.
Но setf его воспринимает совсем по-другому!
ну воспринимает, да.
ты сам можешь кстати setf перегрузить как угодно:
http://www.lispworks.com/documentation/HyperSpec/Body/m_defi_3.htmapply в этом отношении лучше тем, что (apply #'aref array list-of-indexes) - осмысленен (ты по-другому не сможешь вытащить элемент массива если не знаешь заранее его размерность (т. е. число индексов)), а (funcall #'aref array a b c) - не осмысленен, т. к. полностью эквивалентен (aref array a b c). Apply более динамичен в том смысле, что в нём число аргументов, передаваемое функции, определяется в рантайме; наличие funcall обусловлено только раздельными пространствами имён переменных и функций - поэтому, к примеру, в схеме, в которой пространство имён единое, funcall-а нету (ибо нет в нём нужды), а apply - всё равно есть, и всё для тех же целей.