LISP gensym 和 Let 函数的问题
Problem with LISP gensym and Let Functions
我正在开发一个程序项目,该程序采用正则表达式,将它们转换为相应的 NFA,然后允许您测试 NFA 是否接受某些输入字符串。
我正在使用函数 gensym
生成对应于 NFA 状态的数字,只是我喜欢使用 *gensym-counter*
只取它的数字部分,一切都是工作正常,但突然间我遇到了这个奇怪的问题:
我用来调用gensym
的函数是这个
(defun gensympp ()
(let ((x (gensym)))
*gensym-counter*))
所以它 returns 只有在 x
上调用 gensym 后增加的数字,所以我可以将它用于 NFA 状态,今天我是 运行 一些最终测试,突然函数不再增加 *gensym-counter*
所以每个状态都只是起始数字(在函数开始时用 let 设置),解决这个问题的唯一方法似乎是放一个 (defparameter x 1)
(数字没关系)在代码的开头,gensym 正常更新并且一切正常一周前,我也是 lisp 的新手,所以可能只是忽略了一些明显的东西,如果需要,我可以 post 我使用 gensym 的其余代码,但甚至只是调用函数 (gensympp)
本身来自听众不会增加数字
非常感谢您的帮助
我猜你的教授想要的是为每个NFA实例重新枚举状态,从0或1开始。也就是说,状态计数器不是全局变量,而是实例变量在某些 NFA 构造上下文对象中。
(如果你考虑一下,这种一致的编号将使你的 NFA 机器更容易被人类阅读,无论你以何种形式转储它们。如果你两次构建相同的 NFA,两者将在图形形状上一致 和状态的编号。我见过的所有教科书示例都在每个连续的图表中从 0 或 1 开始对状态进行编号。)
另请注意,您可以为 gensym
提供自定义前缀,它可以是一个空字符串:
[1]> (gensym "")
#:3318
除非为了某些数值计算而实际需要状态为整数,否则它们可以只是符号。
编译器正在优化对 gensym
的调用,因为您从不使用 x
。您可以通过将变量作为第二个值返回来欺骗它认为该变量已被使用。
(defun gensympp ()
(let ((x (gensym)))
(values *gensym-counter* x)))
你说你不是要使用全局变量:使用系统提供的全局变量,其实就是使用全局变量。
你应该做的是有一些你传递的状态对象,它跟踪当前计数,并让我们根据需要获取下一个计数。
这可以像整数一样简单,但实际上您可能需要可变的东西。有很多方法可以做到这一点。一个简单的是
(defun make-counter (&key (initial-value 0)
(increment 1))
(let ((current (- initial-value increment)))
(lambda ()
(incf current increment))))
(defun next-count (counter)
(funcall counter))
现在:
> (loop with counter = (make-counter :increment 3)
repeat 4
collect (next-count counter))
(0 3 6 9)
但是还有很多其他的。
在问题中你说你在绑定*gensym-counter*
你自己。好吧,如果那是你正在做的,那么只需使用你自己的特殊变量:它甚至不需要是全局特殊的:
(defmacro with-counter ((&key (initial-value 0)) &body forms)
`(let ((%the-count% (1- ,initial-value)))
(declare (special %the-count%))
,@forms))
(defun next-count ()
(declare (special %the-count%))
(unless (boundp '%the-count%)
(error "not in dynamic extent of WITH-COUNTER"))
(incf %the-count%))
我正在开发一个程序项目,该程序采用正则表达式,将它们转换为相应的 NFA,然后允许您测试 NFA 是否接受某些输入字符串。
我正在使用函数 gensym
生成对应于 NFA 状态的数字,只是我喜欢使用 *gensym-counter*
只取它的数字部分,一切都是工作正常,但突然间我遇到了这个奇怪的问题:
我用来调用gensym
的函数是这个
(defun gensympp ()
(let ((x (gensym)))
*gensym-counter*))
所以它 returns 只有在 x
上调用 gensym 后增加的数字,所以我可以将它用于 NFA 状态,今天我是 运行 一些最终测试,突然函数不再增加 *gensym-counter*
所以每个状态都只是起始数字(在函数开始时用 let 设置),解决这个问题的唯一方法似乎是放一个 (defparameter x 1)
(数字没关系)在代码的开头,gensym 正常更新并且一切正常一周前,我也是 lisp 的新手,所以可能只是忽略了一些明显的东西,如果需要,我可以 post 我使用 gensym 的其余代码,但甚至只是调用函数 (gensympp)
本身来自听众不会增加数字
非常感谢您的帮助
我猜你的教授想要的是为每个NFA实例重新枚举状态,从0或1开始。也就是说,状态计数器不是全局变量,而是实例变量在某些 NFA 构造上下文对象中。
(如果你考虑一下,这种一致的编号将使你的 NFA 机器更容易被人类阅读,无论你以何种形式转储它们。如果你两次构建相同的 NFA,两者将在图形形状上一致 和状态的编号。我见过的所有教科书示例都在每个连续的图表中从 0 或 1 开始对状态进行编号。)
另请注意,您可以为 gensym
提供自定义前缀,它可以是一个空字符串:
[1]> (gensym "")
#:3318
除非为了某些数值计算而实际需要状态为整数,否则它们可以只是符号。
编译器正在优化对 gensym
的调用,因为您从不使用 x
。您可以通过将变量作为第二个值返回来欺骗它认为该变量已被使用。
(defun gensympp ()
(let ((x (gensym)))
(values *gensym-counter* x)))
你说你不是要使用全局变量:使用系统提供的全局变量,其实就是使用全局变量。
你应该做的是有一些你传递的状态对象,它跟踪当前计数,并让我们根据需要获取下一个计数。
这可以像整数一样简单,但实际上您可能需要可变的东西。有很多方法可以做到这一点。一个简单的是
(defun make-counter (&key (initial-value 0)
(increment 1))
(let ((current (- initial-value increment)))
(lambda ()
(incf current increment))))
(defun next-count (counter)
(funcall counter))
现在:
> (loop with counter = (make-counter :increment 3)
repeat 4
collect (next-count counter))
(0 3 6 9)
但是还有很多其他的。
在问题中你说你在绑定*gensym-counter*
你自己。好吧,如果那是你正在做的,那么只需使用你自己的特殊变量:它甚至不需要是全局特殊的:
(defmacro with-counter ((&key (initial-value 0)) &body forms)
`(let ((%the-count% (1- ,initial-value)))
(declare (special %the-count%))
,@forms))
(defun next-count ()
(declare (special %the-count%))
(unless (boundp '%the-count%)
(error "not in dynamic extent of WITH-COUNTER"))
(incf %the-count%))