【发布时间】:2022-01-02 22:11:35
【问题描述】:
重要提示:这个问题完全是因为我想学习 Common Lisp。除了这个自学目标之外,它并没有不可告人的实际目的。
如果在我的 REPL1 中,我评估以下表达式
CL-USER> (random-state-p
#S(random-state
:state #.(make-array 627
:element-type '(unsigned-byte 32)
:initial-element 7)))
...我得到T。换句话说,字面量
#S(random-state
:state #.(make-array 627
:element-type '(unsigned-byte 32)
:initial-element 7))
...计算为有效的random-state 对象。
到目前为止一切顺利。
现在,我尝试定义一个函数silly-random-state,以便表达式(silly-random-state 7) 将产生与上面文字产生的相同的random-state 对象,如下所示:
(defun silly-random-state (some-int)
#S(random-state
:state #.(make-array 627
:element-type '(unsigned-byte 32)
:initial-element some-int)))
...但是我的 REPL 将没有它!它甚至不会评估这个 defun!它抱怨some-int 未定义2。
进一步思考,我想这是有道理的这个宏?
然后我尝试定义一个宏,给定一个整数参数,它将扩展为这样的random-state 对象,如下所示:
(defmacro silly-random-state-macro (some-int)
`#S(random-state
:state #.(make-array 627
:element-type '(unsigned-byte 32)
:initial-element ,some-int)))
再一次,我的 REPL 将没有它。上面表达式的评估失败了
反引号结构中的逗号(不是列表或一般向量。)
上述两个失败中的每一个都会导致一个相应的问题:
- 如何定义一个函数
silly-random-state,它将整数SOME-INT作为参数,并返回random-state,如果我在将PLACEHOLDER替换为整数SOME-INT?
#S(random-state
:state #.(make-array 627
:element-type '(unsigned-byte 32)
:initial-element PLACEHOLDER))
- 如何定义一个宏
silly-random-state-macro以使(silly-random-state-macro some-int)扩展为与 (1) 中描述的相同的random-state对象?
(重复一遍,我的动机只是为了更好地了解 Common Lisp3 能做什么和不能做什么。)
1 SBCL + SLIME/Emacs 在 Darwin 上运行。
2 顺便说一句,我的 REPL 从来没有这么挑剔过!例如,它将评估类似(defun foo () undefined-nonsense) 的内容。当然,它确实对正文中未定义的变量有点不满,但最终它将评估defun。
3 事实上,我曾争论是否应该在这个问题的标签中包含 [prng],因为它的主题实际上是文字、函数和宏,以及 CL 的作用其中的默认 PRNG 只是偶然的。我最终选择保留这个标签,以防 PRNG 在问题中的作用不像我认为的那么偶然。
编辑:好的,我想我找到了一种方法来定义我在(1)中描述的函数;它不是很优雅,但很有效:
(defun silly-random-state (some-int)
(read-from-string
(format nil "#S(random-state :state #.(make-array 627 :element-type '(unsigned-byte 32) :initial-element ~A))" some-int)))
【问题讨论】:
-
阅读器宏
#.表示在阅读时进行评估。在初始情况下,值是在读取时指定的,是固定值。当您将示例转换为defun时,some-int的值在读取时未绑定。只有在调用函数时才绑定。
标签: function random macros common-lisp literals