将变量绑定传递给函数

时间:2019-03-11 10:24:52

标签: binding common-lisp let

我下面有Javascript代码。普通Lisp相当于什么?

function A () {
}
function B () {
}

var a1 = new A();
var b1 = new B();

a1.done.bind(b1);

我要做什么?我需要为要执行的功能传递上下文(上下文中的意思是let创建的变量绑定)。

我有一个函数x1和一个x2,我希望它们可以访问let的变量。问题是我需要将函数作为变量传递。请参阅下面的尝试:

(defmacro create-context (vars &body body)
  `(let ,vars
     ,@body))

(create-context ((x 2) (y 3)) (+ x y))

(defmacro create-suite-context (vars fn)
  (with-gensyms (childs)
    `(let ((,childs '()))
       (create-context
           ,vars
         (push ,fn ,childs)))))

(let* ((a (create-suite-context ((x 2)) (lambda () (+ x 1)))))
  (funcall (car a)))
;; return 3 - OK

(let* ((f (lambda () (+ x 1)))
       (a (create-suite-context ((x 2)) f)))
  (funcall (car a)))
;; The variable X is unbound.

我了解为什么找不到x,原因是这样的:

(let ((f (lambda () (+ x 1))))
  (macroexpand-1 '(create-suite-context
                   ((x 2))
                   f)))
; in: LET ((F (LAMBDA () (+ X 1))))
;     (LET ((F (LAMBDA () (+ X 1))))
;       (MACROEXPAND-1 '(CREATE-SUITE-CONTEXT ((X 2)) F)))
; 
; caught STYLE-WARNING:
;   The variable F is defined but never used.
; in: LET ((F (LAMBDA () (+ X 1))))
;     (+ X 1)
; 
; caught WARNING:
;   undefined variable: X
; 
; compilation unit finished
;   Undefined variable:
;     X
;   caught 1 WARNING condition
;   caught 1 STYLE-WARNING condition
(LET ((#:G591 'NIL))
  (CREATE-CONTEXT ((X 2))
    (PUSH F #:G591)))
T

与此不同:

(macroexpand-1 '(create-suite-context
                 ((x 2))
                 (lambda () (+ x 1))))
(LET ((#:G592 'NIL))
  (CREATE-CONTEXT ((X 2))
    (PUSH (LAMBDA () (+ X 1)) #:G592)))
T

因此,我认为我需要一些“绑定”宏,以便在其中传递“ vars”变量,以便函数可以访问。

注意:我知道我不需要create-context宏,因为它已经完成了let,但是它是为了更好地解释我的上下文意思。

  

@jkiiski回复后向上

我最初想为我的测试框架支持两种不同类型的接口:

(set-ui-cacau 'new-tdd)
(suite :suite-1
       (let ((x y z))
         (test :test-1
               (let ((actual nil))
                 (t-p t))
               :timeout 50)

         (test :test-2
               (let ((actual nil))
                 (t-p t))
               :timeout 70)))
(run-cacau :reporter 'min)

;; or

(set-ui-cacau 'classic)
(in-suite :suite-1
          :timeout 30
          :parent :root)

(test :test-1
      (let ((actual nil))
        (t-p actual))
      :timeout 50)

(test :test-2
      (let ((actual nil)
            (expected 1))
        (setf actual 1)
        (eq-p actual expected))
      :timeout 70)
(run-cacau :reporter 'min)

如您所见,第一个界面更易于操作,因为我有可用的绑定。在第二个接口没有做到这一点的情况下,我也可以包装一个let,但这将消除我也选择实现此接口的原因,这是为了避免嵌套,具体取决于我喜欢阅读的测试在第二个界面上。所以这就是为什么我想到这个问题,其中真正的问题是如何在不使用显式let的情况下将上下文从套件1传递到test-1和test-2。

0 个答案:

没有答案