我明白了……也就是说还是因为他不是函数,返回的也不是函数名,所以就错了.
我的理解错误是因为 C 并不是处处eval的……我一直以为FUNCTION那一坨是被直接扔进了xxx-hook
里……
我明白了……也就是说还是因为他不是函数,返回的也不是函数名,所以就错了.
我的理解错误是因为 C 并不是处处eval的……我一直以为FUNCTION那一坨是被直接扔进了xxx-hook
里……
#'function 不是返回函数名,是返回函数名所指代的函数对象
这个描述不太合理, add-hook 说白了,就是添加一个函数对象,
正儿八经的用法只有两种:
这个更准确的说: 是一个函数调用的表达式, 不是函数
其实我对其也是一知半解,如果 #'function 返回的是函数所指代的对象,那么
(defun a () "return a")
(setq b #'a)
(b) <- 这里却调用出错 Symbol’s function definition is void: b
因为 elisp 是 lisp-2, 就是说, 一个符号既可以表示变量,又可以表示函数
表示变量的时候, 从变量字典里面查询, 表示函数的时候,从函数字典里面查询
(setq b #'a) 是将变量字典里面的 b 设置为 a 对应的函数对象 但执行 (b) 的时候, 是需要从 函数字典里面 找 b 对应的东西,显然没有
因为 symbol 同时有 value slot 和 function slot,设置后者你需要 fset。
Elisp 和 Scheme 不太一样,Scheme 的语法是彻底统一的,所有的语法元素都是 S-expression,define,let 都是 lambda 的语法糖。Elisp 里是区分 函数 和 匿名函数的
(defun hello1 ()
(message "hello"))
(hello1)
;; 也可以 (funcall 'hello1),这也是 add-hook 的函数要 quote 的原因,
;; (如果和Scheme一样是应用序求值,会先对表达式求值,所以如果是 (funcall hello1) ,hello1会先被求值,而 hello1没有返回值,所以会有 void 错误)
;; 可能底层 run-hook 使用的是 funcall 的机制,而 add-hook 里 直接写 lambda 表达式没这个问题
;; Elisp对lambda求值的方式是funcall,(funcall (lambda () (message "hello")))
;; 这就是 Elisp 比 Scheme 蹩脚的地方,Scheme 的求值都是通过括号作用域,是一致的
;; Elisp: (funcall (lambda (x) (message "hello %s" x)) "Jack")
;; Scheme: ((lambda (x) (message "hello %s" x)) "Jack")
(setq hello2 (lambda () (message "hello")))
(funcall hello2)
;; (hello2) error
(funcall b) 就可以, 首先执行 b 的时候,将其作为变量,随意返回值是 变量字典里面的 那个函数对象, funcall 调用这个函数对象,就得到需要的了
你要 (funcall b)
or (fest 'b #'a)
这个说法不太恰当
原来如此,这样就能解释function与普通值之间的区别了,但是为什么这样做呢?
为了让 宏 编写起来更容易,
从以前的文献来看, scheme 选择 lisp-1 是为了让 lisp 更简单,更加适用于递归, 但 lisp-1 相应的也增加了编写宏的难度, common lisp 选择 lisp-2, 虽然让语法稍显丑陋,但降低了宏编写的难度, 只是抉择的侧重,没有对错之分
(define fun-123 () (print 1))
(setq x "123")
(funcall (intern (concat "fun-" x)))
;; => 1
Scheme 要做这个一定要 eval
,但 funcall
效率 是 eval
的几十倍。
这是黑科技, 除非是必须这么搞,否则不要搞这种东西, 容易自残
Real Man doesn’t afraid use of BLACK TECH(e.g. goto).
After all, Lisp is the biggest BLACK TECH.
这个本来就不是函数名: ((lambda () (message “ffff”)))
当eval 上面表达式的时候, 从左到右执行上面表达式的各个子表达式,首先遇到的是lambda表达式,这个表达式执行的结果是它本身对应的函数,执行完后,最后执行总体表达式,就是调用这个函数
而且 add-hook 也不建议使用 lambda