集合形式的评估
Evaluation of setf forms
这个问题是关于 Common Lisp setf
宏,以及它如何计算它的参数形式(和子形式)——也就是说,如果它们碰巧出现不止一次,则只计算一次。 (它也是 Using get-setf-expansion 评论中给出的示例的部分后续。)
;create a list of two hash tables
* (defparameter hts (list (make-hash-table) (make-hash-table)))
HTS
* hts
(#<HASH-TABLE :TEST EQL :COUNT 0 {1007F76CB3}>
#<HASH-TABLE :TEST EQL :COUNT 0 {1007F77103}>)
;define a function that swaps the position of the two hash tables
* (defun next-ht (hts)
(rotatef (first hts) (second hts))
(second hts))
NEXT-HT
交换:
;now do a swap to verify it works
* (next-ht hts)
#<HASH-TABLE :TEST EQL :COUNT 0 {1007F76CB3}>
* hts
(#<HASH-TABLE :TEST EQL :COUNT 0 {1007F77103}>
#<HASH-TABLE :TEST EQL :COUNT 0 {1007F76CB3}>)
;and swap them back
* (next-ht hts)
#<HASH-TABLE :TEST EQL :COUNT 0 {1007F77103}>
* hts
(#<HASH-TABLE :TEST EQL :COUNT 0 {1007F76CB3}>
#<HASH-TABLE :TEST EQL :COUNT 0 {1007F77103}>)
进一步测试:
;then set different values for a key in each table
* (setf (gethash 0 (first hts)) 11)
11
* (setf (gethash 0 (second hts)) 22)
22
* hts
(#<HASH-TABLE :TEST EQL :COUNT 1 {1007F76CB3}>
#<HASH-TABLE :TEST EQL :COUNT 1 {1007F77103}>)
;finally execute a setf with a swapping side-effect
* (setf (gethash 0 (next-ht hts)) (1+ (gethash 0 (next-ht hts))))
23
;but it looks like hts has been swapped twice
;back to its original state
* hts
(#<HASH-TABLE :TEST EQL :COUNT 1 {1007F76CB3}>
#<HASH-TABLE :TEST EQL :COUNT 1 {1007F77103}>)
;also, where did the initial value of 11 go?
* (gethash 0 (first hts))
23
T
* (gethash 0 (second hts))
22
T
*
有人可以澄清发生了什么吗?另外,带有副作用的 setf
表达式是什么意思?
为什么不对 setf
表格进行宏扩展?这里是 LispWorks:
CL-USER 32 > (pprint (macroexpand '(setf (gethash 0 (next-ht hts))
(1+ (gethash 0 (next-ht hts))))))
(LET* ((#:|key1014| 0)
(#:|table1015| (NEXT-HT HTS))
(#:|default1016| NIL)
(#:|store1017| (1+ (GETHASH 0 (NEXT-HT HTS)))))
(SYSTEM::%PUTHASH #:|key1014| #:|table1015| #:|store1017|))
它有什么作用?
- 获取键值
- 获取 hash-table ,调用
NEXT-HT
- 获取默认值,未使用
- 获取新值,调用
NEXT-HT
- 将新的 key/value 存储到 hash-table 中,使用一些特定于实现的方式
很明显 NEXT-HT
被调用了两次。
它背后的粗略 (!) 概念模型是什么?
- setf 将检查第一个表达式。
- 这是什么?哦,是
gethash
,让我为它设置 setter 表格
- 然后 setter 表单将从第一个表单评估必要的子表单
- 然后它将计算新值
- 将使用这些参数调用 setter 运算符。
示例:
CL-USER 62 > (setf (gethash (print 0)
(print (next-ht hts))
(print 1))
(print (1+ (print (gethash 0
(print (next-ht hts))
2)))))
0
#<EQL Hash Table{1} 402000137B>
1
#<EQL Hash Table{0} 4020001573>
2
3
3 ; return value
这个问题是关于 Common Lisp setf
宏,以及它如何计算它的参数形式(和子形式)——也就是说,如果它们碰巧出现不止一次,则只计算一次。 (它也是 Using get-setf-expansion 评论中给出的示例的部分后续。)
;create a list of two hash tables
* (defparameter hts (list (make-hash-table) (make-hash-table)))
HTS
* hts
(#<HASH-TABLE :TEST EQL :COUNT 0 {1007F76CB3}>
#<HASH-TABLE :TEST EQL :COUNT 0 {1007F77103}>)
;define a function that swaps the position of the two hash tables
* (defun next-ht (hts)
(rotatef (first hts) (second hts))
(second hts))
NEXT-HT
交换:
;now do a swap to verify it works
* (next-ht hts)
#<HASH-TABLE :TEST EQL :COUNT 0 {1007F76CB3}>
* hts
(#<HASH-TABLE :TEST EQL :COUNT 0 {1007F77103}>
#<HASH-TABLE :TEST EQL :COUNT 0 {1007F76CB3}>)
;and swap them back
* (next-ht hts)
#<HASH-TABLE :TEST EQL :COUNT 0 {1007F77103}>
* hts
(#<HASH-TABLE :TEST EQL :COUNT 0 {1007F76CB3}>
#<HASH-TABLE :TEST EQL :COUNT 0 {1007F77103}>)
进一步测试:
;then set different values for a key in each table
* (setf (gethash 0 (first hts)) 11)
11
* (setf (gethash 0 (second hts)) 22)
22
* hts
(#<HASH-TABLE :TEST EQL :COUNT 1 {1007F76CB3}>
#<HASH-TABLE :TEST EQL :COUNT 1 {1007F77103}>)
;finally execute a setf with a swapping side-effect
* (setf (gethash 0 (next-ht hts)) (1+ (gethash 0 (next-ht hts))))
23
;but it looks like hts has been swapped twice
;back to its original state
* hts
(#<HASH-TABLE :TEST EQL :COUNT 1 {1007F76CB3}>
#<HASH-TABLE :TEST EQL :COUNT 1 {1007F77103}>)
;also, where did the initial value of 11 go?
* (gethash 0 (first hts))
23
T
* (gethash 0 (second hts))
22
T
*
有人可以澄清发生了什么吗?另外,带有副作用的 setf
表达式是什么意思?
为什么不对 setf
表格进行宏扩展?这里是 LispWorks:
CL-USER 32 > (pprint (macroexpand '(setf (gethash 0 (next-ht hts))
(1+ (gethash 0 (next-ht hts))))))
(LET* ((#:|key1014| 0)
(#:|table1015| (NEXT-HT HTS))
(#:|default1016| NIL)
(#:|store1017| (1+ (GETHASH 0 (NEXT-HT HTS)))))
(SYSTEM::%PUTHASH #:|key1014| #:|table1015| #:|store1017|))
它有什么作用?
- 获取键值
- 获取 hash-table ,调用
NEXT-HT
- 获取默认值,未使用
- 获取新值,调用
NEXT-HT
- 将新的 key/value 存储到 hash-table 中,使用一些特定于实现的方式
很明显 NEXT-HT
被调用了两次。
它背后的粗略 (!) 概念模型是什么?
- setf 将检查第一个表达式。
- 这是什么?哦,是
gethash
,让我为它设置 setter 表格 - 然后 setter 表单将从第一个表单评估必要的子表单
- 然后它将计算新值
- 将使用这些参数调用 setter 运算符。
示例:
CL-USER 62 > (setf (gethash (print 0)
(print (next-ht hts))
(print 1))
(print (1+ (print (gethash 0
(print (next-ht hts))
2)))))
0
#<EQL Hash Table{1} 402000137B>
1
#<EQL Hash Table{0} 4020001573>
2
3
3 ; return value