async.el在Emacs Lisp中说"符号的函数定义是无效的"是什么原因

sav*_*ior 5 emacs asynchronous

我使用异步来调用elisp中的异步函数.

首先,我在github上测试自述文件代码并且运行良好.

然后我写了一个测试代码:

(defun async-function ()
    (async-start
          ;; What to do in the child process
          (lambda ()
                (shell-command-to-string "~/test.sh"))

          ;; What to do when it finishes
          (lambda (result)
                     (message "Async process done, result is: %s" result)))
Run Code Online (Sandbox Code Playgroud)

test.sh代码非常简单:

#! /usr/bin/env sh
sleep 2
echo "shell finish"
Run Code Online (Sandbox Code Playgroud)

它可以工作,但是当我改变这样的lisp代码时失败了:

;;;###autoload
(defun test ()
    (shell-command-to-string "~/test.sh"))

 (defun async-function ()
    (async-start
          ;; What to do in the child process
          (lambda ()
                (test))

          ;; What to do when it finishes
          (lambda (result)
                     (message "Async process done, result is: %s" result)))
Run Code Online (Sandbox Code Playgroud)

结果是:

 error in process sentinel: Symbol's function definition is void: test
Run Code Online (Sandbox Code Playgroud)

我使用该autoload函数加载函数文件,但结果告诉我找不到该文件.

我不知道发生了什么以及如何解决.

Jor*_*ndo 14

async.el的工作原理是生成另一个用于评估表达式的Emacs进程.在这种情况下,您可以在主Emacs进程中定义测试功能,但异步Emacs进程无法访问主进程中的函数和变量.如果要指定要使用的异步调用的函数,请将它们放在文件中并将该文件加载到异步函数中.但请记住,变量等不会转移.

这是一个例子,这是一个文件:

;; ~/.emacs.d/my-functions.el
(defun test ()
  (sit-for 2)
  "Hello, World!.")
Run Code Online (Sandbox Code Playgroud)

这是在其他地方:

;; somewhere else
(async-start
 (lambda ()
   (load-file "~/.emacs.d/my-functions.el")
   (test))
 (lambda (result)
   (message "result: %s" result))) ;; will message hello world
Run Code Online (Sandbox Code Playgroud)

关于共享变量,async不支持此功能.您不能做的是启动一个异步函数,该函数不断修改变量并期望在主emacs进程中访问它,或者甚至只是将变量传递给异步lambda,因为该符号在它打开之前不会被计算它不存在的新过程.

我们可以利用Lisp的反引号语法将我们的变量按值传递给异步函数.下面是在异步函数中使用局部变量和函数的非常hacky方法.

;; We will declare a local variable `myvar'
(setq myvar "Bob")

;; Here is a simple function, notice that it does not
;; refer to other non standard functions or other local variables
(defun hello (name)
  (format "Hello, %s!" name))


(defun my-async-function ()
  (async-start
   ;; notice the backquote!
   `(lambda ()
      ;; in our async lambda we dont use the local `myvar' variable,
      ;; instead we are replacing it with the current local value of `myvar'
      (set  'myvar ,myvar)
      ;; we can also do this by actually obtaining the lambda expression
      ;; behind `hello' and putting that inside our lambda
      (fset 'hello ,(symbol-function 'hello))
      ;; then we wait!
      (sit-for 1)
      ;; now we are modifiying the async copy of `myvar' 
      (setq myvar (concat myvar " Johnson"))
      ;; here we want the result of the async lambda to be a call to our
      ;; `hello' function, but we also want to update our local version
      ;; of myvar with its value in th async process, so we will return
      ;; a list of both values which we can handle in our callback
      (list myvar (hello myvar)))

   (lambda (result)
     ;; once we get the results we'll update our local version of `myvar'
     ;; with the value returned by the async function
     (setq myvar (first result))
     ;; then we can print out the message we recieved from the output
     ;; of our async `hello' call.
     (message "The new value myvar is: %s\nThe result of the function was: %s"
          myvar
          (second result)))))


;; executed top down, the async callback will message:

;;The new value myvar is: Bob Johnson
;;The result of the function was: Hello, Bob Johnson!
Run Code Online (Sandbox Code Playgroud)

我已经用一个宏来抽象出用直接值替换变量和函数的概念:value-bound-lambda,你可以得到宏并在这里看一个例子:

value-bound-lambda示例