У меня есть код Javascript ниже.Что было бы эквивалентно в Common 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
Поэтому я думаю, что мне понадобится некоторый макрос «bind», в котором я мог бы передать переменные «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, но это убрало бы причину, по которой я также решил реализовать этот интерфейс, то есть избежать вложенности, в зависимости от тестов, которые я предпочитаю читатьна втором интерфейсе.Вот почему я задал этот вопрос, где реальная проблема заключается в том, как я мог бы передать контекст из suite-1 в test-1 и test-2 без использования явного let.