Я пишу программу на Common Lisp, которая должна хранить кучу битов состояния для очень большого количества записей в массиве (вся программа в значительной степени fortran-in-lisp), а биты состояния закодированы как биты фиксированного числа, находящиеся в этом массиве. Аксессоры для этих битов состояния на самом деле будут определяться макросом, поэтому мне не нужно заботиться о распределении битов, но функция считывателя образцов может быть
(defun deadp (e)
(logbitp 0 e))
(в реальной жизни это будет быть встроенными и загроможденными объявлениями, чтобы попытаться убедиться, что это быстро, но я думаю, здесь это не имеет значения.)
Мне нужно, чтобы эти вещи были функциями, потому что я хочу иметь возможность отображать их, но также потому, что Мне становится плохо от использования макроса для встроенной функции.
Тогда я буду использовать это как-то так:
(defconstant status-index 3)
...
(dotimes (i nentries)
(unless (deadp (aref entries i status-index))
...))
(На самом деле life (aref entries i status-index)
будет (status entries i)
, который, в свою очередь, потребует метода setf
, но я думаю, что это легко.)
или
(loop for i below nentries
counting (if (deadp entries i status-index) 1 0))
И, конечно, будет быть другими аналогичными однобитными флагами, которые будут иметь разные биты, связанные с ними.
Итак, теперь я хочу иметь возможность сделать это:
(dotimes (i nentries)
...
(when ...
(setf (deadp (aref entries i status-index) t)))
...)
, который должен превратиться в код, эквивалентный
(dotimes (i nentries)
...
(when ...
(progn
(setf (ldb (byte 1 0) (aref entries i status-index)) 1)
t))
...)
А также это:
(let ((status 0))
...
(when ...
(setf (deadp status) t))
...)
который ш может превратиться в код, эквивалентный этому:
(let ((status 0))
...
(when ...
(progn
(setf (ldb (byte 1 0) status) 1)
t))
...)
Другими словами, я хочу, чтобы моя функция deadp
была аксессором, а setf
на ней работала в общем для нее: (setf (deadp (cdr x)) nil)
должно работать, et c.
Итак, это сбило меня с толку в части CL, которую я избегал долгое время: определение расширителей setf
. Совершенно очевидно, что простое определение функции (setf deadp)
не будет работать, потому что числа неизменны, и я достаточно уверен, что defsetf
недостаточно мощный, поэтому мне нужно define-setf-expander
, чего я не делаю. Не понимаю.
Может кто-нибудь объяснить, как мне это нужно делать? Я думаю, что конкретная функция deadp
не критична, хотя все функции, которые меня волнуют, будут выглядеть как ее варианты.
Альтернативный ответ был бы «это безумный подход, вместо этого ... . ', и я открыт для них. Я подумал о написании кода, который абстрагирует массив, поэтому вместо (deadp (aref ...))
я бы написал (deadp people ...)
, где people
- это массив людей. Это было бы хорошо, и легко увидеть, как сделать это setf
способным, за исключением того, что я также хочу иметь возможность сказать (deadp status)
, где status
- это просто фиксированное число. Но, возможно, есть подход получше.