elisp 中的 lambda 函数作用域

lambda function scope in elisp

我在设计程序时犯了一个错误。 我需要按值对散列 table 中的部分条目进行排序。 我会用演示代码来讲述这个故事。

;; A loacal hash table......
(let ((table (make-hash-table))
      (list-of-interest nil))

  (puthash 0 "Foo" table)
  (puthash 1 "Bar" table)
  ;;..........
  (puthash 9999 "Bra" table)

  ;; And I have a list with key I am interested to sort
  (dotimes (var 50)
    (add-to-list list-of-interest (random 9999)))

  ;; Sorting should depends on comparing the associated string
  ;; For exmple,
  ;; If the list is (0 1 9999)
  ;; I hope to get (1 9999 0) as "Bar" < "Bra" < "Foo"

  ;; However, I forgot that the table is a local variable
  ;; I can't pass the table to the predicate function by any means
  ;; So the predicate function can never resolve the string from the key
  (sort list-of-interest 'predicate)

  ;; When I was thinking to rewrite the code
  ;; I find that a lambda function can 'grab' the local variable
  (sort list-of-interest (lambda (a b)
                           (string-lessp (gethash a table) (gethash b table))))
  ;; return value
  table)

我在心里提出了两个问题:

  1. 最重要的问题:lambda函数可以吗?
  2. 我相信 lambda 是一个像其他函数一样没有名字的函数。为什么它可以'grab'局部变量?

是的,你的 lambda 函数没问题。

Emacs Lisp 有两种类型的绑定:动态绑定和词法绑定。动态绑定是默认设置,您可以通过将此行添加为 Emacs Lisp 源文件的第一行来在每个文件的基础上激活词法绑定:

;;; -*- lexical-binding: t; -*-

(这会将本地缓冲区中的变量 lexical-binding 设置为 t。)

您的 lambda 函数可以正确处理动态绑定和词法绑定。

它与动态绑定一起工作正常,因为该函数仅在 sort 函数运行时被调用,并且在其执行期间有一个名为 table 的 let-bound 变量,其中包含所需的值.

它与词法绑定一起工作正常,因为该函数在词法上位于绑定 tablelet 内部,因此该函数可以访问该变量的值。


您的代码有一处错误:您应该将 sort 的结果赋值给变量:

(setq list-of-interest (sort list-of-interest ...))

sort 通过重新排列其 cons 单元对列表进行排序,但不能保证将源列表中的第一个 cons 单元重用为目标列表中的第一个 cons 单元。如果您不将结果分配回去,您可能在某些情况下 "lose" 一些列表元素。