Common lisp setf表格的评估
这个问题是关于公共LispCommon lisp setf表格的评估,common-lisp,expression-evaluation,setf,Common Lisp,Expression Evaluation,Setf,这个问题是关于公共Lispsetf宏,以及它如何计算其参数形式(和子形式)——也就是说,如果它们碰巧出现多次,则只计算一次。(这也是对评论中给出的示例的部分后续。) ;创建两个哈希表的列表 *(定义参数hts(列表(生成哈希表)(生成哈希表))) 高温超导 *高温超导 (# #) ;定义一个交换两个哈希表位置的函数 *(卸载下一个ht(hts) (rotatef(第一hts)(第二hts)) (第二个hts) 下一代 交换: ;now do a swap to verify it works
setf
宏,以及它如何计算其参数形式(和子形式)——也就是说,如果它们碰巧出现多次,则只计算一次。(这也是对评论中给出的示例的部分后续。)
;创建两个哈希表的列表
*(定义参数hts(列表(生成哈希表)(生成哈希表)))
高温超导
*高温超导
(#
#)
;定义一个交换两个哈希表位置的函数
*(卸载下一个ht(hts)
(rotatef(第一hts)(第二hts))
(第二个hts)
下一代
交换:
;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}>)
;现在做一次交换来验证它是否有效
*(下一个ht hts)
#
*高温超导
(#
#)
;然后把它们换回来
*(下一个ht hts)
#
*高温超导
(#
#)
进一步测试:
;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(gethash 0(第一个hts))11)
11
*(setf(gethash 0(第二个hts))22)
22
*高温超导
(#
#)
;最后执行一个带有交换副作用的setf
*(setf(gethash 0(下一个ht hts))(1+(gethash 0(下一个ht hts)))
23
;但看起来hts已经换了两次了
;恢复原状
*高温超导
(#
#)
;还有,11的初始值到哪里去了?
*(gethash 0(第一个hts))
23
T
*(gethash 0(第二个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|))
它有什么作用
- 获取键值
- 获取哈希表,调用
NEXT-HT
- 获取默认值,不使用
- 获取新值,调用
NEXT-HT
- 使用特定于实现的方式将新的键/值存储到哈希表中
NEXT-HT
被调用了两次
它背后的粗略(!)概念模型是什么
- setf将检查第一个表达式
- 这是什么?哦,它是
,让我为它设置setter表单gethash
- 然后,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
CL-USER 62>(setf(gethash)(打印0)
(打印(下一个ht hts))
(打印件1)
(打印(1+)(打印(gethash 0
(打印(下一个ht hts))
2)))))
0
#
1.
#
2.
3.
3.返回值
为什么不宏扩展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|))
它有什么作用
- 获取键值
- 获取哈希表,调用
NEXT-HT
- 获取默认值,不使用
- 获取新值,调用
NEXT-HT
- 使用特定于实现的方式将新的键/值存储到哈希表中
NEXT-HT
被调用了两次
它背后的粗略(!)概念模型是什么
- setf将检查第一个表达式
- 这是什么?哦,它是
,让我为它设置setter表单gethash
- 然后,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
CL-USER 62>(setf(gethash)(打印0)
(打印(下一个ht hts))
(打印件1)
(打印(1+)(打印(gethash 0
(打印(下一个ht hts))
2)))))
0
#
1.
#
2.
3.
3.返回值
SETF
不会阻止子窗体被计算两次。修改宏,比如INCF
这样做。@jkiiski这就是我想要的区别。我以前的印象是,setf
是一种修改宏,因为这个位置只是传递给get setf expansion
。谢谢。SETF
不会阻止子窗体被计算两次。修改宏,比如INCF
这样做。@jkiiski这就是我想要的区别。我以前的印象是,setf
是一种修改宏,因为这个位置只是传递给get setf expansion
。谢谢。感谢您总结了setf
评估模型。但是我试图更好地理解(参考上面的代码回顾文章)为什么acelent明确建议使用setf表达式而不是使用get setf expansion
编写自己的修改宏。这是因为您自己必须小心地只对子窗体求值一次get setf expansion
不会为您执行此操作。是这样吗?这可能有点“离题”,但我希望看到类似的get setf expansion
操作摘要。我花了一段时间在上面的代码审查帖子中挖掘信息,现在我意识到我真的不需要问这个问题。大多数答案已经存在。请随意删除它,如果您有任何补充,也可以将其用于进一步的教育目的。但感谢您的时间、努力和澄清。感谢您总结了setf
评估模型。但是我试图更好地理解(参考上面的代码回顾文章)为什么acelent明确建议使用setf表达式而不是使用get setf expansion
编写自己的修改宏。这是因为您自己必须小心地只对子窗体求值一次get setf expansion
不会为您执行此操作。是这样吗?这可能有点“离题”,但我希望看到类似的get setf expansion
操作摘要。我花了一段时间在上面的代码审查帖子中挖掘信息,现在我意识到我真的不需要问这个问题