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,

Все еще много работы. Я надеюсь, что кто-то еще делает / сделал это:)

Другие вопросы по тегам