Прежде всего, нельзя недооценивать важность стиля. Мы пишем код не только для запуска компьютеров, но, что гораздо важнее, для чтения людьми. Кодекс, читаемый и понятный для людей, является очень важным аспектом разработки программного обеспечения.
Во-вторых, да, есть большая разница между (setf fdefinition)
и defun
.
«малые» различия в том, что defun
могут также установить doc string имени функции (на самом деле, в зависимости от того, как работает ваш imeplementation, он может сделать это с лямбда также), и создает именованный block
(видел в macroexpansions ниже), которые в противном случае вам нужно было бы создать, если хотите.
Большая разница в том, что компилятор «знает» около defun
и обработает его соответствующим образом.
Например, если ваш файл
(defun foo (x)
(+ (* x x) x 1))
(defun bar (x)
(+ (foo 1 2 x) x))
тогда компилятор может предупредить вас, что вы называете foo
в bar
с неправильным количеством аргументов:
ВНИМАНИЕ: в BAR в строках 3 ..4: FOO вызывается с тремя аргументами, но для этого требуется 1 аргумент. [FOO был определен в строках 1..2]
Если заменить defun foo
с (setf (fdefinition 'foo) (lambda ...))
, компилятор вряд ли с ним обращаться так же тщательно.Кроме того, вы, вероятно, получите предупреждение вдоль линий
Следующие функции использовались, но не определено: FOO
Вы можете исследовать то, что defun
делает в вашей реализации по macroexpanding это:
(macroexpand-1 '(defun foo (x) "doc" (print x)))
CLISP расширяет его
(LET NIL (SYSTEM::REMOVE-OLD-DEFINITIONS 'FOO)
(SYSTEM::EVAL-WHEN-COMPILE
(SYSTEM::C-DEFUN 'FOO (SYSTEM::LAMBDA-LIST-TO-SIGNATURE '(X))))
(SYSTEM::%PUTD 'FOO
(FUNCTION FOO
(LAMBDA (X) "doc" (DECLARE (SYSTEM::IN-DEFUN FOO)) (BLOCK FOO (PRINT X)))))
(EVAL-WHEN (EVAL)
(SYSTEM::%PUT 'FOO 'SYSTEM::DEFINITION
(CONS '(DEFUN FOO (X) "doc" (PRINT X)) (THE-ENVIRONMENT))))
'FOO)
SBCL делает:
(PROGN
(EVAL-WHEN (:COMPILE-TOPLEVEL) (SB-C:%COMPILER-DEFUN 'FOO NIL T))
(SB-IMPL::%DEFUN 'FOO
(SB-INT:NAMED-LAMBDA FOO
(X)
"doc"
(BLOCK FOO (PRINT X)))
(SB-C:SOURCE-LOCATION)))
Дело в том, что defun
имеет много «под капотом», и по причине. setf fdefinition
, с другой стороны, больше «то, что вы видите, это то, что вы получаете», т. Е. Никакой магии.
Это не означает, что setf fdefinition
не место в современной кодовой базе. Вы можете использовать его, например, чтобы реализовать «бедняк trace
» (непроверенный):
(defun trace (symbol)
(setf (get symbol 'old-def) (fdefinition symbol)
(fdefinition symbol)
(lambda (&rest args)
(print (cons symbol args))
(apply (get symbol 'old-def) args))))
(defun untrace (symbol)
(setf (fdefinition symbol) (get symbol 'old-def))
(remprop symbol 'odd-def))
DEFUN также создать именованный блок. Нужно добавить это к лямбде. –