不同之处在于,使用间接,您可以使用其他代码来更改主函数将返回的内容。考虑,例如,
(defun get-fn-1 ()
(let ((fn (lambda () 42)))
(prog1 fn
(setq fn (lambda () 43)))))
(funcall (get-fn-1))
;=> 42
因为fn
首先计算变量,然后返回值(返回 42 的函数),所以当您调用 的结果时get-fn-1
,您会得到42
,即使您fn
随后分配了一个新函数。另一方面,如果您返回一个调用 的函数fn
,那么稍后对 的更改将fn
反映在返回的函数中。
(defun get-fn-2 ()
(let ((fn (lambda () 42)))
(prog1 (lambda () (funcall fn))
(setq fn (lambda () 43)))))
(funcall (get-fn-2))
;=> 43
要查看差异真正有意义的地方,您需要一个更大的示例。这是您获得两个功能的一个:一个是“状态功能”,它告诉您您处于什么状态,另一个是应该在状态之间“循环”您。虽然它有问题:
(defun get-state-fn-buggy ()
(let* ((state-fns (list (lambda () 'state-1)
(lambda () 'state-2)
(lambda () 'state-3)))
(state-fn (first state-fns)))
;; make the list circular, and then return as multiple values a
;; state function, and a function to cycle the state functions.
(nconc state-fns state-fns)
(values state-fn
(lambda () (setq state-fn (pop state-fns))))))
(multiple-value-bind (state cycle)
(get-state-fn-buggy)
(list (funcall state)
(progn (funcall cycle) (funcall state))
(progn (funcall cycle) (funcall state))
(progn (funcall cycle) (funcall state))))
;=> (state-1 state-1 state-1 state-1)
; uh oh, we wanted different states
更好的实现返回一个使用间接作为状态函数的新函数,以便“幕后”修改state-fn
反映在我们得到的状态函数中。
(defun get-state-fn ()
(let* ((state-fns (list (lambda () 'state-1)
(lambda () 'state-2)
(lambda () 'state-3)))
(state-fn (first state-fns)))
;; make the list circular, and then return as multiple values a
;; state function, and a function to cycle the state functions.
(nconc state-fns state-fns)
(values (lambda () (funcall state-fn))
(lambda () (setq state-fn (pop state-fns))))))
(multiple-value-bind (state cycle)
(get-state-fn)
(list (funcall state)
(progn (funcall cycle) (funcall state))
(progn (funcall cycle) (funcall state))
(progn (funcall cycle) (funcall state))))
;=> (state-1 state-1 state-2 state-3)
; good, now cycle has an effect on state