如何在plist循环中创建定时器?Lisp代码类型错误排查
问题分析与解决
核心原因
sb-ext:make-timer的第一个参数要求是函数对象或者符号,你传入的(print "first")是一个表达式(列表),不属于要求的类型,因此触发类型错误。而硬编码的(lambda () ...)是一个匿名函数对象,符合参数要求,所以能正常执行。
解决方案
有两种常见的修正方式:
方式1:用eval执行传入的表达式
将每个待执行的表达式包装进无参lambda,通过eval执行:
(defun run-timeline (timeline) "Timeline is a plist with alternating timecodes and code to execute" (alexandria:doplist (time form timeline) (sb-ext:schedule-timer (sb-ext:make-timer (lambda () (eval form)) :thread t) time))) (run-timeline '(0 (print "first") 2 (print "second")))
这种方式保持了调用时的简洁性,但要注意eval会在全局环境中执行代码,若表达式依赖词法作用域内的变量,可能无法正确引用。
方式2:传入函数对象而非表达式
调整调用方式,直接传入lambda函数对象,函数内部无需eval:
(defun run-timeline (timeline) "Timeline is a plist with alternating timecodes and code to execute" (alexandria:doplist (time form timeline) (sb-ext:schedule-timer (sb-ext:make-timer form :thread t) time))) (run-timeline '(0 (lambda () (print "first")) 2 (lambda () (print "second"))))
这种方式更符合Lisp函数式编程的风格,避免了eval的潜在问题,适合处理包含闭包变量的复杂逻辑。
内容的提问来源于stack exchange,提问作者kflak
相关产品推荐
相关产品推荐

