我从来没有能够提出一种方法来穿透set-process-sentinel
层次结构,其中包含函数开头定义的let-bound变量 - 只有缓冲区本地或全局变量可以穿透它。允许绑定变量可以达到第一个start-process
,但这是因为无法识别而无法被拒绝 - 在函数开始时定义的let-bound变量 似乎无法穿透以(lambda (p e) . . .
开头的部分。任何人都可以想到一种方法,包括穿透嵌套哨兵,如下例所示?
(set-process-sentinel
(start-process
"my-process-name-one"
"*OUTPUT-BUFFER*"
"/path/to/executable"
"argument-one"
"argument-two"
"argument-three")
(lambda (p e) (when (= 0 (process-exit-status p))
(set-process-sentinel
(start-process
"my-process-name-two"
nil ;; example of not using an output buffer
"/path/to/executable"
"argument-one"
"argument-two"
"argument-three")
(lambda (p e) (when (= 0 (process-exit-status p))
(set-process-sentinel
(start-process . . . ))))))))
答案 0 :(得分:7)
问题是Emacs Lisp变量绑定默认是动态的。也就是说,在评估函数时,在定义函数的环境中,但在调用函数的环境中,查找绑定变量 not 。
Emacs 24或更高版本本身支持词法绑定(即函数看到函数 definition 中绑定的变量),但由于它改变了现有代码的语义,因此需要启用它明确。通常,这是通过将文件局部变量设置添加到.el
文件的第一行来完成的:
;; -*- lexical-binding: t; -*-
另一种方法是使用lexical-let
库中的cl
。这也适用于早期的Emacs版本。请注意,通过这种方式,您可以明确指定哪些变量应该具有词法绑定,因此(lexical-let ((foo foo)) ...)
之类的代码并不罕见 - foo
是一个现有的变量,需要进行“转移”。进入功能。
答案 1 :(得分:2)
以下是使用动态绑定的示例:
(defun example-dynamic-fn ()
"Doc-string"
(interactive)
(let ((test-variable "Hello-world!"))
(set-process-sentinel
(start-process "process-one" "*one*" "echo" test-variable)
`(lambda (p e) (when (= 0 (process-exit-status p))
(set-process-sentinel
(start-process "process-two" "*two*" "echo" ,test-variable)
'(lambda (p e) (when (= 0 (process-exit-status p))
(start-process "process-three" "*three*" "echo" ,test-variable)
(set-process-sentinel
(start-process "process-four" "*four*" "echo" ,test-variable)
'(lambda (p e) (when (= 0 (process-exit-status p))
(set-process-sentinel
(start-process "process-five" "*five*" "echo" ,test-variable)
'(lambda (p e) (when (= 0 (process-exit-status p))
(message "test-variable: %s" ,test-variable)))))))))))))))
答案 2 :(得分:1)
;;; ensure VAR1 has no binding
(makunbound 'VAR1)
;;;
(defun f1 (&optional VAR1)
(interactive)
(unless VAR1
(set 'VAR1 "variable1"))
(pop-to-buffer "*test*")
; (lexical-let ( (VAR1 VAR1) ) ;;;
(set-process-sentinel
(start-process-shell-command "test"
"*test*"
(concat "echo " VAR1))
(lambda (process event)
(condition-case err
(when (string-match-p "finished" event)
(f2 VAR1))
(error
(princ
(format "Sentinel error: %s" err))))))
; ) ;;;
)
;;;
(defun f2 (&optional VAR2)
(interactive)
(unless VAR2
(set 'VAR2 "VARIABLE2"))
(print VAR2))
我们加载所有内容((f1)
注释掉的行)并运行(f1)
。在发生错误之前,VAR1
的值会传递给(f2)
。错误(void-variable VAR1
)似乎来自(set-process sentinel PROCESS SENTINEL)
的范围环境; VAR1
未定义SENTINEL
,即使它仍在(lambda)
((set )
)函数的范围内。
如果变量只是要使函数具有局部范围,那么同样使用;
并不是最佳实践。
如果我们取消注释标有(set-process sentinel )
的行,那么一切都按预期工作。令人高兴的是,我们可以将值传递给另一个函数,这会阻止一系列SENTINEL
的长期构建。如果需要,它还允许我们使用其他子流程生成流程。
我的一个错误是将(lexical-let )
命名为离散函数,而不是将其保留在lexical-binding: t;
函数中。虽然(let )
方法很有吸引力,但它往往会破坏依赖于标准{{1}}的工作代码。