2017-11-22 2 views
2

아래 코드에서와 같이 하나의 인수를 허용하는 클로저를 만드는 함수를 정의합니다.이 값은이 클로저의 컨텍스트에서 바인드 된 변수를 나타내는 기호입니다. 클로저의 본문에서는 symbol-value을 사용하여 심볼 값을 가져 오지만 Symbol's value as variable is void이라는 오류 메시지가 표시되면이 스 니펫이 123으로 표시 될 것으로 예상됩니다.Elisp에서 클로저에서 로컬로 바인딩 된 심볼의 값 셀에 액세스하는 방법은 무엇입니까?

  1. symbol-value이 작동하지 않는 이유 :

    그래서 나는 여기 두 가지 질문이 있습니까?

  2. 원하는 스 니펫을 수정하여 원하는 결과를 얻으려면 어떻게해야합니까? 업데이트
    (defun make-closure() 
        (lexical-let ((var1 123)) 
        (lambda (name) 
         ;; How can I get the value cell of the symbol 
         ;; specified by the argument "name" ? 
         ;; This doesn't work. 
         (message-box (format "%s" (symbol-value name)))))) 
    
    (let ((closure (make-closure))) 
        (funcall closure 'var1)) 
    

: 나는 모방 "객체 지향"일부 장난감 코드를 작성할 때

사실,이 질문이 있어요. 처음에는 ( 스테판의 대답의 두 번째 코드와 유사하다)이 같은했다 :

(defun new-person (initial-name) 
    (lexical-let* ((name initial-name) 
       (say-hi (lambda() 
          (message-box (format "Hi, I'm %s" name)))) 
       (change-name (lambda (new-name) 
           (setq name new-name)))) 
    (lambda (selector &rest args) 
     (cond 
     ((equal 'say-hi selector) (apply say-hi args)) 
     ((equal 'change-name selector) (apply change-name args)) 
     (t (message-box "Message not understood")))))) 

(let ((tony (new-person "Tony"))) 
    (funcall tony 'say-hi) 
    (funcall tony 'change-name "John") 
    (funcall tony 'say-hi)) 

을하지만 "COND"좀 "상용구"의 조항을 느꼈다 나는 이 가능한 수 있습니다 그것을 생각 인수에서 전달 된 기호를 사용, 그래서 더 이상 작동 다음, 그것을 수정,하지만 난 왜 알아낼 수 없습니다 :

(defun new-person (initial-name) 
    (lexical-let* ((name initial-name) 
       (say-hi (lambda() 
          (message-box (format "Hi, I'm %s" name)))) 
       (change-name (lambda (new-name) 
           (setq name new-name)))) 
    (lambda (selector &rest args) 
     (apply (symbol-value selector) args)))) 

그래서 우리가 사용하지 않도록 말을하는 것입니다 어휘 적으로 바운드 변수 인 을 참조하는 기호 위와 같이 닫는다. 평가에서 그들 중 이라는 이름은 그들 자신이 과 똑같은 것으로 보증 되었기 때문에 말이다.

+0

어휘 변수는 단순히 클로저 외부에서 액세스 할 수있는 것은 아닙니다. 그것은 다소 중요합니다. 이러한 변수에 액세스해야하는 경우 어휘 바인딩은 처음에는 잘못된 선택이었으며 그 방법을 찾기 위해 시도하는 것이 좋은 생각이라고 생각하지 않습니다. – phils

답변

2

당신은 여기에 몇 가지 오해했지만, 중요한 것은 당신이 (funcall closure 'var1)으로 전달하고있는 var1 심볼이 람다 함수가 정의 된 어휘 환경에서 하지 기호는 것입니다.

매크로 확장 어휘형은 명확히하는 데 도움이됩니다. 이 :

(lexical-let ((var1 123)) 
    (lambda (name) 
    (message-box (format "%s" (symbol-value name))))) 

이 라인을 따라 확장됩니다

(가) lexical-let 매크로 충돌하지 않는 방식으로 당신이 바인딩에서 지정한 심볼 이름을 다시는-쓰는 말을하는 것입니다
(progn 
    (defvar --cl-var1--) 
    (let ((--cl-var1-- 123)) 
    #'(lambda (name) 
     (message-box (format "%s" (symbol-value name)))))) 

.

실제로는 이 완료되었으므로의 모든 항목이 var1 인 것을 유의하십시오. 완료했다면 코드에서 --cl-var1--에 대한 추가 참조를 볼 수 있습니다. 이 기능에 기호 var1를 통과하면

, 당신은 정식var1하지 --cl-var1--을 전달하는 (또는 무엇이든은 실제로 었죠).

이것이 전부입니다. 어휘 바인딩의 본질은 해당 범위 내에서 작성된 코드에 영향을 미치고 이 아니고이 코드 외부에 영향을 미친다는 것입니다. (let ((closure (make-closure))) (funcall closure 'var1)) 양식이 바깥에 있으므로 어휘 바인딩 된 var1이 전혀 표시되지 않습니다.


는 코드를 "수정"에 올 때, 나는 오히려 당신이 갈하려는 위치를 알아 내기 위해 사투를 벌인거야,하지만 내 해석이 전혀 클로저를 싶지 않을 것이다 당신 때문에 어휘 바인딩보다 동적 바인딩을 찾고 있습니다. 예컨대 : 질문에 대한 편집을 바탕으로

(defun make-func() 
    (lambda (name) 
    (message-box (format "%s" (symbol-value name))))) 

(let ((func (make-func)) 
     (var1 123)) 
    (funcall func 'var1)) 

, 나는 당신이 함수 인수에 일치하려는 값을 바인딩 어휘 사용되지 않도록 약간의 코드를 재 작업 제안했다. 예를 들어 :

(defun new-person (initial-name) 
    (lexical-let* 
     ((name initial-name) 
     (map (list 
      (cons 'say-hi (lambda() 
          (message-box 
           (format "Hi, I'm %s" name)))) 
      (cons 'change-name (lambda (new-name) 
            (setq name new-name)))))) 
    (lambda (selector &rest args) 
     (apply (cdr (assq selector map)) args)))) 
+0

+1 마지막 단락과 최종 코드에 대해, 그리고 그 질문이 너무 명확하지 않다는 것을 언급하기 위해. – Drew

1

어휘 적 바인딩 변수는 근본적으로 이름이없는 (즉, 자신의 이름은 평가시 소스 코드에 존재하지만 존재하지 일시적인 유물이다).

;; -*- lexical-binding:t -*- 

(defun make-closure() 
    (lambda (ref) 
    ;; How can I get the value cell of the symbol 
    ;; specified by the argument "name" ? 
    ;; This doesn't work. 
    (message-box (format "%s" (gv-deref ref))))) 

(let ((closure (make-closure))) 
    (let ((var1 123)) 
    (funcall closure (gv-ref var1)))) 

을하지만, 그렇지 않으면 내가 외부에서에 심판을받을 수 없기 때문에 var1의 결합하자를 이동했다 참고 :

대신 변수에 참조를 사용할 수 있습니다. 나는 두 개의 서로 다른 목적을 위해 var1을 사용

(defun make-closure() 
    (lexical-let ((var1 123)) 
    (lambda (name) 
     ;; How can I get the value cell of the symbol 
     ;; specified by the argument "name" ? 
     ;; This doesn't work. 
     (message-box (format "%s" (pcase name 
           ('var1 var1) 
           (_ (error "Unknown var name %S" name)))))))) 

(let ((closure (make-closure))) 
    (funcall closure 'var1)) 

참고 :이 어휘 VAR의 이름은 일단, 다른 시간 그건 당신이 수동으로 어휘 변수에 이름을 부여하는

또 다른 옵션은 어떤 var를 사용할지를 선택하는 데 사용되는 심볼이고 pcase은 하나를 다른 것으로 변환합니다. 우리는 어휘 적으로 바운드 된 var에 대해 "any"다른 이름을 사용할 수 있으며 코드는 외부 호출자를 변경하지 않고도 똑같이 잘 작동합니다. .

관련 문제