使用<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<img id="model" name="wiz" src="http://tive.pl/model.png" usemap="#wizualizacja"/>
<img id="spodnie" name="wiz" src="http://tive.pl/spodnie.png" usemap="#wizualizacja"/>
<map name="wizualizacja">
<area shape="poly" coords="119,800,114,758,111,737,111,736,106,719,102,706,98,689,95,670,92,657,91,639,93,637,93,636,96,636,98,636,100,636,101,636,103,636,104,636,106,635,106,635,107,634,107,635,108,635,109,636,111,637,113,637,114,637,116,637,117,637,119,637,120,637,122,637,124,637,126,637,128,638,130,638,133,638,136,638,140,638,142,638,144,637,145,635,147,634,148,631,149,630,151,618,153,609,153,601,154,599,156,605,159,609,160,611,161,613,162,614,164,616,168,619,173,621,177,622,181,623,185,623,187,623,188,623,188,634,267,634,267,620,285,620,285,642,285,643,285,644,286,644,286,646,285,667,284,675,283,691,283,698,282,701,282,705,282,707,282,720,282,727,282,730,282,733,283,739,283,742,283,743,282,753,282,756,282,758,283,760,284,766,285,769,285,771,285,774,285,776,286,778,286,779,286,781,286,787,287,789,287,792,288,794,288,796,288,798,288,800" alt="spodnie" title="spodnie" id="area"/>
</map>
和defun
定义的函数的基本区别如下所示,并且除了样式考虑之外,还有一种优先于另一种方法的方法吗?
使用setf
:
defun
使用* (defun myfirst (l)
(car l) )
MYFIRST
* (myfirst '(A B C))
A
:
setf
如果根据Wikipedia:
通过使用defun宏将lambda表达式存储在符号中来创建命名函数
使用* (setf (fdefinition 'myfirst) #'(lambda (l) (car l)))
#<FUNCTION (LAMBDA (L)) {10021B477B}>
* (myfirst '(A B C))
A
以不同方式创建变量需要使用setf
:
funcall
我的理解是这种类型的变量与前一种变量不同,因为在Why multiple namespaces?中描述的与defun绑定符号相同的名称空间中找不到此变量。
答案 0 :(得分:7)
首先,永远不要低估风格的重要性。 我们编写代码不仅仅是为了运行计算机,更重要的是,让人们阅读。 使代码可读并且易于理解是软件开发的一个非常重要的方面。
其次,是的, (setf fdefinition)
和defun
之间存在很大差异。
“小”差异是defun
也可以设置函数名称的doc string(实际上,取决于你的imeplementation如何工作,它也可以用lambda来做),并创建一个名为block
(见下面的宏扩展),如果你愿意,你可以自己创建。
最大的区别是编译器“知道”defun
并且会适当地处理它。
,例如,如果您的文件是
(defun foo (x)
(+ (* x x) x 1))
(defun bar (x)
(+ (foo 1 2 x) x))
然后编译器可能会警告您,使用错误的参数数量在foo
中调用bar
:
警告:在第3..4行的BAR中:使用3个参数调用FOO,但它需要1 论点。 [FOO在第1..2行中定义]
如果用defun foo
替换(setf (fdefinition 'foo) (lambda ...))
,编译器不太可能小心处理它。此外,你可能会得到一个警告
使用了以下功能但未定义: FOO
您可能希望通过macroexpanding检查defun
在您的实施中的作用:
(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
在现代的lisp代码库中没有位置。你可以使用它,例如,实现“穷人的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))