Можно ли использовать макрос для создания комбинаций c […] r с любым произвольным количеством вызовов car и cdr, таких как cadaddr?

#macros #scheme #lisp #common-lisp #cdr

#макросы #схема #шепелявый #common-lisp #cdr

Вопрос:

Недавно я обнаружил, что все мои реализации Scheme выдают ошибку при попытке использования (cadaddr (list 1 3 (list 5 7) 9)) . По-видимому, по умолчанию схема не допускает никаких car cdr комбинаций and в однофункциональной форме, которые используют более четырех сокращенных car cdr вызовов and. Первоначально я винил в этом минимализм Scheme, но затем обнаружил, что Common Lisp также разделяет этот недостаток.

Можно ли это решить с помощью макроса? Можем ли мы написать макрос, который допускает произвольное количество a и d в своих c[...]r вызовах и возвращает ожидаемый результат, а также имеет совместимость с Common Lisp-подобными макросами, такими как setf ? Если нет, то почему бы и нет? И если да, была ли когда-либо указана причина, по которой это не является функцией по умолчанию ни в одном lisp, который я видел?

Ответ №1:

Такой макрос описан в разделе Let Over Lambda для common lisp. Вы должны обернуть свой код с (with-cxrs ...) помощью, чтобы включить их все в область видимости, но он просматривает ваш код, чтобы увидеть, какие комбинаторы вам нужны. Я написал его порт на Clojure много лет назад для развлечения, хотя, конечно, никто (включая меня) никогда не хотел использовать его по-настоящему. Вы могли бы перенести его в Scheme, если хотите.

 (defn cxr-impl [name]
  (when-let [op (second (re-matches #"c([ad] )r" name))]
    `(comp ~@(map {a `first d `rest} op))))

(defmacro with-cxrs [amp; body]
  (let [symbols (remove coll? (tree-seq coll? seq body))]
    `(let [~@(for [sym symbols
                   :let [impl (cxr-impl (name sym))]
                   :when impl
                   thing [sym impl]]
               thing)]
       ~@body)))

user> (macroexpand-1 '(with-cxrs (inc (caadaaddadr x))))
(let [caadaaddadr (comp first first rest first first rest rest first rest)]
  (inc (caadaaddadr x)))
 

https://groups.google.com/g/clojure/c/CanBrJPJ4aI/m/S7wMNqmj_Q0J

Как отмечалось в ветке списка рассылки, есть некоторые ошибки, которые вам придется устранить, если вы хотите использовать это по-настоящему.