Emacs Lisp: Предупреждение байт-компилятора для неопределенных функций в apply, mapcar
Когда вы выполняете вызов функции (myfunction ...
) в emacs lisp, байтовый компилятор предупредит, если неизвестно, будет ли определена функция во время компиляции. Это очень помогает с нисходящим стилем программирования, так как тогда я могу с удовольствием написать
(defun foo (bar baz)
(foo-filter-by-functon (lambda (a b) (equal (upcase a) (upcase b)))
(foo-combine-values bar baz)))
Когда я компилирую, байтовый компилятор говорит мне, что я еще не определил или неправильно написал два foo-
функции.
Однако, если лямбда-выражение становится сложным, имеет смысл провести еще одну реструктуризацию, например
(defun foo (bar baz)
(foo-filter-by-functon 'foo-equal
(foo-combine-values bar baz)))
Теперь есть проблема, хотя... 'foo-equal
теперь является символом и только во время выполнения при выполнении foo-filter-by-function
проверка, является ли 'foo-equal
определяется будет выполнен. То, что обычно является предупреждением во время компиляции, внезапно стало ошибкой во время выполнения. Та же проблема применяется для встроенных функций высшего порядка, таких как mapcar
, apply
...
Есть ли возможность заставить байт-компилятор распознавать, например, первый аргумент mapcar
должна быть функцией и, таким образом, когда аргумент задан как символ, проверьте, имеет ли этот символ правильное определение функции, как это происходит с явным (foo-equal ..)
звонки?
Примечание: цель состоит в том, чтобы сделать рабочий код более читабельным, поэтому решения, которые требуют изменения каждого вызова foo-filter-by-function
или хакерский код в своем определении не являются приемлемыми решениями. Примером такого контрпродуктивного решения будет
(defun foo (bar baz)
(foo-filter-by-functon (lambda (a b) (foo-equal a b)) ... )
(foo-combine-values bar baz)))
или же
(defun foo (bar baz)
(foo-filter-by-functon foo-equal
(foo-combine-values bar baz)))
(defconst foo-equal (lambda (a b) ...)
поскольку оба приводят к ухудшению читаемости кода, по крайней мере, субъективно.
2 ответа
Вы хотите использовать #'foo-equal
вместо 'foo-equal
чтобы сказать компилятору, что вы не просто говорите о foo-equal
символ, но о foo-equal
функция.
Мне кажется, что вы касаетесь статического / динамического языкового вопроса.
Код
(defun foo (bar baz)
(foo-filter-by-functon 'foo-equal
(foo-combine-values bar baz)))
это совершенно законный код, который вытекает из его гибкости. Существуют правовые ситуации, когда foo-equal
не должны быть определены. Я думаю, что ты имел в виду
(defun foo (bar baz)
(foo-filter-by-functon #'foo-equal
(foo-combine-values bar baz)))
Это все еще законный код LISP. Могут быть ситуации, хотя и меньше, когда foo-equal
не должны быть определены.
Главное
Это foo-filter-by-functon
это решает, будет ли вызван его аргумент или нет, поэтому логично, что он должен проверить аргумент перед вызовом: может быть, что-то вроде этого:
(defun-carefully
`(defun foo-filter-by-function (fun lst)
(cl-remove-if-not fun lst)))
куда defun-carefully
является макросом, который будет определять функцию и сохранять в некотором выражении, что он вызывает ее первый аргумент. Как он узнал, что называет свой аргумент? Это выглядело в том же духе, что cl-remove-if-not
называет свой аргумент.
И если все defuns обернуты этим макросом, возможно, возможно получить те предупреждения, которые вы хотите. Может быть, это можно переопределить defun
временно с macrolet
на время eval-buffer
,
Все еще много работы. Я надеюсь, что кто-то еще делает / сделал это:)