2016-08-21 13 views
4

В Common Lisp, если я хочу две функции разделить состояние, я бы выполнить Пусть над лямбда следующим образом:let-over-lambda в схеме?

(let ((state 1)) 
(defun inc-state() 
    (incf state)) 
(defun print-state() 
    (format t "~a~%" state)) 

Эти функции не являются локальными по отношению к let - они являются глобальными функциями, которые поддерживают ссылка на общее состояние , которое само не видно снаружи. Например, я мог бы сделать следующее в другом месте в моем коде:

(print-state)  => 1 
(inc-state)   => 2 
(print-state)  => 2 

В схеме, однако, такая конструкция объявляет локальные функции, которые не видны снаружи:

(let ((state 1)) 
(define (print-state) 
    (print state)) 

(print-state))  => 1 

(print-state)  => error, no such variable print-state 

только как я могу думать, чтобы достичь такой функциональности (в стороне от использования не-экспортироваться глобал внутри модуля), будет что-то вроде этого:

(define print-state #f) 
(define inc-state #f) 

(let ((state 1)) 
(set! print-state (lambda() (print state))) 
(set! inc-state (lambda() (inc! state)))) 

Есть ли способ в схеме написать форму let-over-lambda, не прибегая к таким уродливым обходным решениям? Или мне нужно написать макрос, чтобы обернуть это уродство? (Кстати, я знаю о letrec, и это не решение этой проблемы.)

Кстати, я использую куриную схему, но мой вопрос должен иметь отношение ко всем схемам.

ответ

3

К сожалению, верхний уровень связывания может быть сделано только верхний уровень и define внутри процедуры на самом деле просто синтаксический сахар для letrec. В Chicken Scheme у вас есть форма под названием define-values, где вы можете сделать это:

(define-values (print-state inc-state) 
    (let ((state 1)) 
    (values (lambda() (print state)) 
      (lambda() (inc! state))))) 

define-values Обратите внимание, что не является частью какого-либо стандарта, даже если это кажется, что это общая форма, чтобы иметь. Было бы легко сделать макрос, который использует подход, который вы использовали для его реализации. В качестве альтернативного решения можно вернуть диспетчер, что вы называете, чтобы получить доступ к процедуре:

(define dispatcher 
    (let ((state 1)) 
    (lambda (msg) 
     (case msg 
     ((print) (lambda() (print state))) 
     ((inc!) (lambda() (inc! state))))))) 

(define print-state (dispatcher 'print)) 
(define inc-state (dispatcher 'inc!)) 

В действительности вам не нужно делать глобал, так как вы можете просто позвонить возвращению непосредственно:

((dispatcher 'inc!)) 
((dispatcher 'inc!)) 
((dispatcher 'print)) ; ==> prints 3 
+0

Благодарю. 'define-values' менее уродливое, чем мое решение. Я все же, вероятно, напишу макрос, чтобы его обернуть. –

+0

'define-values' указан в разделе 5.3.3 R7RS. –

3

Вы могли бы сделать что-то вроде этого:

(define-values (inc-state print-state) 
    (let ((state 1)) 
    (values 
    (lambda() ; inc-state 
     (set! state (+ 1 state))) 
    (lambda() ; print-state 
     (display state) 
     (newline))))) 

> (print-state) 
1 
> (inc-state) 
> (print-state) 
2 
> state 
. . state: undefined; cannot reference an identifier before its definition 
> 

(выход из Ракетка, но я тестировал в Chicken Scheme а)

 Смежные вопросы

  • Нет связанных вопросов^_^