Emacs Lisp: #s does not create a new hash table each time

余生长醉 提交于 2019-12-10 14:47:15

问题


I have the following function:

(defun inc-map ()
  (let ((ht #s(hash-table test contents-hash))) 
    (dolist (i (list 1 2 3 4))
      (let ((old-val (or (gethash "foo" ht)
             0)))
    (puthash "foo" (+ 1 old-val) ht)))
    ht))

Despite the fact that this function seems to define the ht symbol locally, the function doesn't seem to be referentially transparent. In particular, calling it once returns the hash table "foo" -> 4, calling it a second time returns "foo" -> 8, a third time returns "foo" -> 12 and so on.

What exactly is going on here and how do I change this function to be referentially transparent (and return "foo" -> 4 every time)?


回答1:


This might be considered a (slight) documentation bug, in that it suggests a little too firmly that using the printed representation creates a new hash table -- a statement which is open to misinterpretation.

However, you'll note that the documentation says that it's the elisp reader that recognises the printed representation of a hash table.

Therefore using #s is not the same as calling make-hash-table. The difference here is equivalent to the difference between quoting a list '(1 2 3) and calling (list 1 2 3).

The former in each case is processed by the reader and hence the same, single resulting object (hash table or list respectively) is seen during each evaluation.

Conversely, in the latter instances the reader is generating code which, when evaluated, will create a new hash table or list; and therefore you see a new object during each evaluation.



来源:https://stackoverflow.com/questions/36964728/emacs-lisp-s-does-not-create-a-new-hash-table-each-time

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!