2013-04-17 2 views
2

Этот вопрос аналогичен по возможности: In R6RS Scheme, is there a way to get the current environment for use with eval?, но я хотел бы сделать еще один шаг и спросить, как вы исправили бы что-то вроде этого.Использование переменных let в схеме лямбда в схеме

Моя проблема еще более смущена тем, что в моем случае '(+ x y) является произвольным неоценимым заявлением лямбда. Неоценим, потому что он может содержать вызовы переменных, которые являются частью let (и поскольку Scheme не верит, что процедура будет вызвана в среде, содержащей эти переменные, когда текущий нет, он отключает неопределенную ошибку идентификатора) , Поэтому возникает вопрос: как я могу реструктурировать свой код, чтобы этот кошмар с прицелом больше не был проблемой? Я бы все еще мог использовать переменные окружения из let, когда вызывается лямбда.

Я использую Pretty Big

Цель состоит в том, чтобы создавать классы на схеме. Мой подход до сих пор является довольно большим (не каламбур), но выглядит следующим образом:

(define (dispatch msg methods args) 
     (if (null? methods) (display "Method signature not found.") 
      (let (
       (m-name (caar methods)) 
       (m-args (cadar methods)) 
       (m-body (caddar methods))) 
      (if (and (eq? msg (caar methods)) (eq? (length args) (length (cadar methods)))) 
       `(lambda ,m-args ,m-body) 
       (dispatch msg (cdr methods) args))))) 

    (define (build-lets c-def) 
     (let (
      (i-vars (cadr c-def)) 
      (meths (caddr c-def))) 
     (eval `(append ',i-vars (list (list 'methods '',meths)))))) 

    (define (new c-def . args) 
     (apply (eval `(lambda ,(map cadr (cadr c-def)) 
       (let* ,(build-lets c-def) 
       (lambda (msg . args) 
        (letrec ((meth (dispatch msg methods args))) 
        (apply meth args)))))) 
      args)) 

где с четкостью является классом размораживание формы (скажем, для точки)

'(();Name of parent 
     ((yvalue y) (xvalue x)) ;Instance variables: (i-var constructor-arg) 
     ((getx() xvalue) ;Methods, ((name args body) ...) 
     (setx (x) (set! xvalue x))))) 
+0

Я не уверен, что вы пытаетесь сделать, у вас есть пример кода? –

+0

@ ChrisJester-Young Я думаю, он хочет найти способ, чтобы что-то вроде '(let ((x 1)) (eval '(* x 2)))' будет возвращать '2'. –

+0

@Maxwell это точно правильно – JPatnode

ответ

3

Это Безразлично» t реализуйте весь синтаксис, который вы имеете в виду, но он может проиллюстрировать методы, необходимые для его чистки.

(define-syntax make-object 
    (syntax-rules() 
    [(__ ([ivar ival] ...) ([method-name args body ...] ...)) 
     (let ([ivar ival] ...) 
     (λ (msg . oargs) 
      (cond 
      [(eq? 'method-name msg) 
       (apply (λ args body ...) oargs)] ... 
      [else 
       (error 'object-system "unknown message" msg)])))])) 

(define o (make-object ([xvalue 'x]) 
         ([getx() xvalue] 
         [setx (x) (set! xvalue x)]))) 

(o 'getx) => x 
(o 'setx 'blah) 
(o 'getx) => blah 

Хитрость заключается в том, чтобы написать макрос, который делает закрытие. Переменные экземпляра входят в лексическую область (let), которая содержит замыкание. Закрытие - диспетчер. Методы - это lambdas, определенные в диспетчере, поэтому переменные экземпляра находятся в той же области, что и методы.

+0

Это именно то, что мне нужно, чтобы заставить меня двигаться в правильном направлении. Благодаря! – JPatnode

0

Если вы можете сделайте let часть eval, тогда он будет работать. Ниже приведен пример:

Нечто подобное (но проще) к коду, который не работает:

(define (hello m) 
    (let ((msg m)) 
    (eval '(print msg)))) 

Изготовление пусть часть Eval сделать это работает:

(define (hello m) 
    (eval `(let ((msg ,m)) 
      (print msg)))) 
Смежные вопросы