如何使用 Emacs Lisp 动态范围? [英] How to live with Emacs Lisp dynamic scoping?

查看:18
本文介绍了如何使用 Emacs Lisp 动态范围?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我以前学过 Clojure 并且非常喜欢这门语言.我也喜欢 Emacs,并且用 Emacs Lisp 破解了一些简单的东西.不过,有一件事让我在精神上无法用 Elisp 做任何更实质性的事情.这是动态范围的概念.我只是害怕它,因为它对我来说太陌生了,而且闻起来像半全局变量.

I've learned Clojure previously and really like the language. I also love Emacs and have hacked some simple stuff with Emacs Lisp. There is one thing which prevents me mentally from doing anything more substantial with Elisp though. It's the concept of dynamic scoping. I'm just scared of it since it's so alien to me and smells like semi-global variables.

所以对于变量声明,我不知道哪些事情是安全的,哪些是危险的.据我所知,用 setq 设置的变量属于动态范围(对吗?) let 变量呢?我在某处读到 let 允许您进行简单的词法范围界定,但在其他地方我读到 let vars 也是动态范围的.

So with variable declarations I don't know which things are safe to do and which are dangerous. From what I've understood, variables set with setq fall under dynamic scoping (is that right?) What about let variables? Somewhere I've read that let allows you to do plain lexical scoping, but somewhere else I read that let vars also are dynamically scoped.

我最担心的是我的代码(使用 setq 或 let)不小心破坏了我调用的平台或第三方代码中的一些变量,或者在这样的调用之后,我的局部变量被意外弄乱了.我怎样才能避免这种情况?

I quess my biggest worry is that my code (using setq or let) accidentally breaks some variables from platform or third-party code that I call or that after such call my local variables are messed up accidentally. How can I avoid this?

是否有一些简单的经验法则可以让我遵循并确切地知道示波器会发生什么,而不会以某种奇怪的、难以调试的方式被咬住?

Are there a few simple rules of thumb that I can just follow and know exactly what happens with the scope without being bitten in some weird, hard-to-debug way?

推荐答案

还不错.

函数中的自由变量"可能会出现主要问题.

The main problems can appear with 'free variables' in functions.

(defun foo (a)
  (* a b))

在上面的函数中 a 是一个局部变量.b 是一个自由变量.在像 Emacs Lisp 这样具有动态绑定的系统中,b 将在运行时被查找.现在分三种情况:

In above function a is a local variable. b is a free variable. In a system with dynamic binding like Emacs Lisp, b will be looked up at runtime. There are now three cases:

  1. b 未定义 -> 错误
  2. b 是由当前动态范围内的某个函数调用绑定的局部变量 -> 取该值
  3. b 是一个全局变量 -> 取那个值
  1. b is not defined -> error
  2. b is a local variable bound by some function call in the current dynamic scope -> take that value
  3. b is a global variable -> take that value

问题可能是:

  • 绑定值(全局或本地)被函数调用遮蔽,可能不需要
  • 未定义的变量不会被隐藏 -> 访问错误
  • 全局变量没有被隐藏 -> 获取全局值,这可能是不需要的

在带有编译器的 Lisp 中,编译上述函数可能会生成一个警告,提示存在自由变量.通常 Common Lisp 编译器会这样做.解释器不会提供该警告,只会在运行时看到效果.

In a Lisp with a compiler, compiling the above function might generate a warning that there is a free variable. Typically Common Lisp compilers will do that. An interpreter won't provide that warning, one just will see the effect at runtime.

建议:

  • 确保您不会意外使用自由变量
  • 确保全局变量有一个特殊的名字,这样它们在源代码中很容易被发现,通常是*foo-var*

不要写

(defun foo (a b)
   ...
   (setq c (* a b))  ; where c is a free variable
   ...)

写:

(defun foo (a b)
   ...
   (let ((c (* a b)))
     ...)
   ...)

绑定所有要使用的变量,并且要确保它们没有绑定到其他地方.

Bind all variables you want to use and you want to make sure that they are not bound somewhere else.

基本上就是这样.

由于 GNU Emacs 版本 24 词法绑定在其 Emacs Lisp 中得到支持.请参阅:词法绑定,GNU Emacs Lisp 参考手册.

Since GNU Emacs version 24 lexical binding is supported in its Emacs Lisp. See: Lexical Binding, GNU Emacs Lisp Reference Manual.

这篇关于如何使用 Emacs Lisp 动态范围?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆