在定义中使用自身的Lisp变量



我正在使用LTK库在Lisp中构建一个窗口应用程序。我想要一个按钮,它可以执行操作,并且可能隐藏自己。然而,这个代码:

(let* ((left (button 0 0 f "←" #'(lambda ()
(decf start page-length)
(funcall redraw)
(if (>= start page-length)
(ltk:configure left :state :visible))
(ltk:configure left :state :hidden))))))

声称";"左";是一个未定义的变量(其余的在超出此问题范围的代码中定义(。

在最坏的情况下,我会避免";按钮";函数,并针对这种特殊情况重新编写代码,但该场景需要一个通用的解决方案。在Lisp中,有没有任何方法可以在变量的定义中使用函数中的变量?

只有一个绑定的let*let绑定相同。在执行主体之前,let绑定不存在。在执行button期间,left的引用必须来自较早的闭包或全局,因为left是在表达式求值后创建的。你可以这样做:
(let ((left nil))
(setf left (button 0 0 f "←" #'(lambda ()
(decf start page-length)
(funcall redraw)
(if (>= start page-length)
(ltk:configure left :state :visible)
(ltk:configure left :state :hidden))))))

注意:if中有一个错误,导致lambda总是执行(ltk:configure left :state :hidden)

这里值得一提的是CL:中的letrec版本

(defmacro letrec (bindings &body decls/forms)
(assert (and (listp bindings)
(every (lambda (b)
(or (symbolp b)
(and (consp b)
(symbolp (first b))
(null (cddr b)))))
bindings))
(bindings) "malformed bindings")
(multiple-value-bind (names values)
(loop for b in bindings
collect (etypecase b
(symbol b)
(cons (first b)))
into vars
collect (etypecase b
(symbol nil)
(cons (second b)))
into vals
finally (return (values vars vals)))
`(let ,names
(psetf ,@(loop for name in names
for val in values
collect name
collect val))
(locally
,@decls/forms))))

然后

> (letrec ((x (lambda (y)
(if (null y)
'done
(funcall x (cdr y))))))
(funcall x '(1 2 3)))
done

最新更新