add-hook和lambda ?

and FUNCTION may be any valid function.

所以说1楼的代码不套lambda最后会报错的原因还是因为——它根本不是个函数,而是个S-expression ?

这样我就明白咋回事情了……

返回的根本不是个函数

你是想说它不是个有效的 Lisp 语句?

所以它是啥?

也就是说,(函数 ‘参数)并不是一个函数名,但是他还是一个函数语句?

虽然可以直接如此调用它
((lambda () (when sanityinc/initial-frame (run-after-make-frame-hooks sanityinc/initial-frame))))
我个人觉得这个并不算函数名,至少从直觉上来说。语义上另当别论

以 Emacs Lisp 的语义來說,因為 #'(lambda ...) 返回 (lambda ...),而 #'function 的定义是 返回 函数名,就是如此。或者說我说的「函数名」,就是 function 返回的那個東西。

而且在这里這樣解釋更方便理解。


Common Lisp 之類其實不是這樣。

[40]> #'(lambda (x) (+ x 1))
#<FUNCTION :LAMBDA (X) (+ X 1)>
[41]> (lambda (x) (+ x 1))
#<FUNCTION :LAMBDA (X) (+ X 1)>

這個打印為 #<FUNCTION :LAMBDA (X) (+ X 1)> 的物件才是它名字。

不是啊,我现在能理解的「函数」是C的「函数」……所以我在说「函数」的时候指的也指C的「函数」。

看来我得去补补lisp基础课了……

====== update ========

也就是说,add-hook加进xxx-hook里的东西,是FUNCTION那一坨的返回值,而且返回值需要是函数

(函数 ’参数)(qoute (函数 ‘参数))这样的东西返回的都不是函数 ,所以当然就会出现错误?

对对。


我一开始就感覺你受 C 荼毒太重。

我确实受C荼毒很重……

也就是说,add-hook并不是直接就把FUNCTION的那一坨直接扔到xxx-hook里,而是添加了FUNCTION的 返回值


(函数 '参数)这种东西,其实也是函数,只不过不是我理解的那种 函数,而更像我理解的 语句

是的。虽然 C 也是以 return value 為主,但 Lisp 几乎处处都是 return value,函数的参数都要 evaluate。

不是,這就是你理解出錯的原因。

一个合 Lisp 语法的 S-exp 就是个 Lisp 语句,只是因為 Lisp 的函数参数都要 evaluate,所以语句也能做参数。

我明白了……也就是说还是因为他不是函数,返回的也不是函数名,所以就错了.

我的理解错误是因为 C 并不是处处eval的……我一直以为FUNCTION那一坨是被直接扔进了xxx-hook里……

1 个赞

#'function 不是返回函数名,是返回函数名所指代的函数对象

2 个赞

这个描述不太合理, add-hook 说白了,就是添加一个函数对象,

正儿八经的用法只有两种:

  1. (add-hook 'xxx #'function)
  2. (add-hook 'xxx (lambda () (fsfsdf)))

这个更准确的说: 是一个函数调用的表达式, 不是函数

其实我对其也是一知半解,如果 #'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 对应的东西,显然没有

1 个赞

因为 symbol 同时有 value slot 和 function slot,设置后者你需要 fset。

1 个赞

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
1 个赞

(funcall b) 就可以, 首先执行 b 的时候,将其作为变量,随意返回值是 变量字典里面的 那个函数对象, funcall 调用这个函数对象,就得到需要的了

你要 (funcall b) or (fest 'b #'a)

这个说法不太恰当