Common Lisp: запись лямбда функций

в 19:32, , рубрики: Песочница, метки: , ,

Частый вопрос начинающих лисперов:
в чём отличие записи #'(lambda (x) (expr x)) от (lambda (x) (expr x))? И как правильно писать?

В CL есть специальный оператор function аргументом которого может быть символ или не вычисляемая форма вида (lambda ...).
Результатом вычисления function является функция-объект к которой можно применить apply или funcall.
#' — стандартный макрос Lisp считывателя (reader macro) который раскрывается в (function ...)
Поэтому #'(lambda (x) (expr x)) есть ни что иное, как (function (lambda (x) (expr x))).
Также стандартом определён макрос lambda, который раскрывается в (function (lambda ...)) или кратко #'(lambda ...).

Строго говоря, следующие выражения семантически равнозначны:

(lambda (x) (expr x))
#'(lambda (x) (expr x))
(function (lambda (x) (expr x)))

Вопрос, как наиболее корректно с эстетической (в плане синтаксиса) точки зрения записывать лямбда функции, остаётся открытым и, по всей видимости, не будет закрыт никогда.
С одной стороны, запись вида #'(lambda (x) (expr x)) симметрична записи #'f и код, в этом смысле, выглядит однородно.
С другой стороны, макросы генерирующие лямбда функции наподобие lambda-match из optima никаким образом не могут быть записаны с префиксом #' (function ничего не знает о таких формах, как lambda-match). В этом случае однородно выглядит использование lambda макроса вместе с другими макросами которые раскрываются в лямбда функции.

Один подход:

(let ((xs (list 1 2 3 4 5 6)))
  (mapcar #'(lambda (x)
              (+ x 2))
          (remove-if #'oddp xs)))
;; (4 6 8)

Другой подход:

(let ((xs (list 1 2 3 4 5)))
  (mapcar (lambda (x)
            (+ x 2))
          (remove-if (lambda-match
                       (1 nil)
                       (2 nil)
                       (x   x))
                     xs)))
;; (3 4)

Я предпочитаю использовать lambda макрос.

Поделиться

* - обязательные к заполнению поля