2012-02-08 2 views
5

은 가정하자 나는이 빈약 샘플 같은 정원 - 다양한 폐쇄가 어딘가에 (해시 테이블에서). 그럼 난 잠시 동안 (funcall)이 인스턴스를하지 않습니다. 그런 다음 해시 테이블에서이 인스턴스를 검색하고 반환 된 값 4를 반환하여 (funcall)을 다시 검색합니다.클로저가 어떻게 자체를 참조 할 수 있습니까?</p> <pre><code>(let ((alpha 0) #| etc. |#) (lambda() (incf alpha) #| more code here |# alpha)) </code></pre> <p>한다고 가정 내가 <code>(funcall)</code>이 폐쇄 3 회 예, 세 번째 실행의 중간에, 이것은 폐쇄 자체를 저장하고 싶어 :

클로저의 함수가 자체를 참조하여 해시 테이블에 저장되는 방식은 무엇입니까?

편집 1 : 다음은 좀 더 자세한 예입니다. 클로저를 매개 변수로 전달하여 목표를 달성합니다. 그러나 클로저가 자기 매개 변수화없이이 모든 것을 자체적으로 수행하고 싶습니다.

1 (defparameter *listeriosis* nil) 
2 (defparameter *a* 
3 (lambda() 
4  (let ((count 0)) 
5  (lambda (param1 param2 param3 self) 
6   (incf count) 
7   (when (= 3 count) 
8   (push self *listeriosis*) 
9   (push self *listeriosis*) 
10   (push self *listeriosis*)) 
11   count)))) 
12 (let ((bee (funcall *a*))) 
13 (princ (funcall bee 1 2 3 bee)) (terpri) 
14 (princ (funcall bee 1 2 3 bee)) (terpri) 
15 (princ (funcall bee 1 2 3 bee)) (terpri) 
16 (princ (funcall bee 1 2 3 bee)) (terpri) 
17 (princ (funcall bee 1 2 3 bee)) (terpri)) 
18 (princ "///") (terpri) 
19 (princ (funcall (pop *listeriosis*) 1 2 3 nil)) (terpri) 
20 (princ (funcall (pop *listeriosis*) 1 2 3 nil)) (terpri) 
21 (princ (funcall (pop *listeriosis*) 1 2 3 nil)) (terpri) 
1 
2 
3 
4 
5 
/// 
6 
7 
8 

편집 2 : 네, 나는 그것의 첫 번째 매개 변수에 함수의 이름을 미끄러 다음 (funcall) 대신이 매크로를 사용하는 매크로를 사용할 수 있습니다 알고 있지만 나는 아직도 방법을 알고 싶습니다 클로저가 자신의 인스턴스를 참조하도록합니다.

편집 3 : SK 로직의 친절한 제안에 따라 다음을 수행했지만 원하는대로하지 않았습니다. 스택에 3 개의 새로운 클로저를 푸시하지만 동일한 클로저에 대한 세 개의 참조는 푸시하지 않습니다. 스택에서 꺼낼 때 호출 값이 6, 7 및 8 대신 1, 1 및 1 인 방법을 확인하십시오.

1 (defparameter *listeriosis* nil) 
2 (defun Y (f) 
3 ((lambda (x) (funcall x x)) 
4 (lambda (y) 
5  (funcall f (lambda (&rest args) 
6    (apply (funcall y y) args)))))) 
7 (defparameter *a* 
8 (lambda (self) 
9  (let ((count 0)) 
10  (lambda (param1 param2 param3) 
11   (incf count) 
12   (when (= 3 count) 
13   (push self *listeriosis*) 
14   (push self *listeriosis*) 
15   (push self *listeriosis*)) 
16   count)))) 
17 (let ((bee (Y *a*))) 
18 (princ (funcall bee 1 2 3 #| bee |#)) (terpri) 
19 (princ (funcall bee 1 2 3 #| bee |#)) (terpri) 
20 (princ (funcall bee 1 2 3 #| bee |#)) (terpri) 
21 (princ (funcall bee 1 2 3 #| bee |#)) (terpri) 
22 (princ (funcall bee 1 2 3 #| bee |#)) (terpri)) 
23 (princ "///") (terpri) 
24 (princ (funcall (pop *listeriosis*) 1 2 3)) (terpri) 
25 (princ (funcall (pop *listeriosis*) 1 2 3)) (terpri) 
26 (princ (funcall (pop *listeriosis*) 1 2 3)) (terpri) 
1 
2 
3 
4 
5 
/// 
1 
1 
1 

편집 4 : Jon O의 제안이 정확하게 기록되었습니다.

1 (defparameter *listeriosis* nil) 
2 (defparameter *a* 
3 (lambda() 
4  (let ((count 0)) 
5  (labels ((self (param1 param2 param3) 
6     (incf count) 
7     (when (= 3 count) 
8     (push (function self) *listeriosis*) 
9     (push (function self) *listeriosis*) 
10     (push (function self) *listeriosis*)) 
11     count)) 
12   (function self))))) 
13 (let ((bee (funcall *a*))) 
14 (princ (funcall bee 1 2 3)) (terpri) 
15 (princ (funcall bee 1 2 3)) (terpri) 
16 (princ (funcall bee 1 2 3)) (terpri) 
17 (princ (funcall bee 1 2 3)) (terpri) 
18 (princ (funcall bee 1 2 3)) (terpri)) 
19 (princ "///") (terpri) 
20 (princ (funcall (pop *listeriosis*) 1 2 3)) (terpri) 
21 (princ (funcall (pop *listeriosis*) 1 2 3)) (terpri) 
22 (princ (funcall (pop *listeriosis*) 1 2 3)) (terpri) 
1 
2 
3 
4 
5 
/// 
6 
7 
8 

편집 5 : MIRON의 제안도 마크 안타, 실제로 좀 더 읽을 수있는 코드를 만들어 다음은 코드와 출력의

1 (defmacro alambda (parms &body body) 
2 `(labels ((self ,parms ,@body)) 
3  #'self)) 
4 ; 
5 (defparameter *listeriosis* nil) 
6 (defparameter *a* 
7 (lambda() 
8  (let ((count 0)) 
9  (alambda (param1 param2 param3) 
10   (incf count) 
11   (when (= 3 count) 
12   (push #'self *listeriosis*) 
13   (push #'self *listeriosis*) 
14   (push #'self *listeriosis*)) 
15   count)))) 
16 ; 
17 (let ((bee (funcall *a*))) 
18 (princ (funcall bee 1 2 3)) (terpri) 
19 (princ (funcall bee 1 2 3)) (terpri) 
20 (princ (funcall bee 1 2 3)) (terpri) 
21 (princ (funcall bee 1 2 3)) (terpri) 
22 (princ (funcall bee 1 2 3)) (terpri)) 
23 (princ "///") (terpri) 
24 (princ (funcall (pop *listeriosis*) 1 2 3)) (terpri) 
25 (princ (funcall (pop *listeriosis*) 1 2 3)) (terpri) 
26 (princ (funcall (pop *listeriosis*) 1 2 3)) (terpri) 
1 
2 
3 
4 
5 
/// 
6 
7 
8 
+0

당신은 "익명 함수"를 의미한다. 어쨌든, 나는 왜 당신이 단순히 그 이름을 말하지 않을 것이라고 생각하지 않습니까? – delnan

+0

나는 클로저의 새로운 인스턴스를 원하지 않는다. 내가 둘러싼 변수를 계속 변경하면서 오래된 것을 원한다. 실제로, 여러 인스턴스가있을 수 있으며, 각 인스턴스는 어딘가에서 소금으로 처리되어야합니다. 이름을 밝히면서이 모든 작업을 수행 할 수 있습니까? 문법은 무엇입니까? –

+0

나는 lisp을 아주 잘 말하지 않지만 JavaScript에서 흔히 볼 수있는 "self-executing function expressions"같은 것이이 트릭을 수행한다고 가정합니다. – delnan

답변

4

alambda (On Lisp에도 해당)은 무엇인가요? 나는 "폐쇄"로 가정

;; Graham's alambda 
(defmacro alambda (parms &body body) 
    `(labels ((self ,parms ,@body)) 
    #'self)) 
+0

나는 이것을 EDIT 5에서 사용했다. 실제로 코드를 더 읽기 쉽게 만듭니다. 감사! –

+2

글쎄, 그것은 '라벨'아이디어에 대한 가장 일반적인 구현입니다. 또한'blambda'가 유용 할 것입니다. 여기서'self'라는 이름을 얻을 수 있습니다. 이에 대한 더 많은 예제는 [Alexandria] (http://common-lisp.net/project/alexandria/draft/alexandria.html)를 참조하십시오 ('if-let'을 찾으십시오). –

+2

예'blambda' :'(defmacro blambda (fn-name args & body body) )''(라벨 ((, fn-name, args, @ body)) # ', fn-name))' (fact (x) (if (= 0 x) 1 (* x (사실 (1- x)))))) 5)' –

7

을 당신이로 갈 필요가 있다고 생각하지 않습니다 이것을하기 위해서 너 자신을 위해 Y 결합자를 정의하는 것; labels 양식에 내장되어 있으면 필요한 자체 참조 바인딩이 만들어집니다. HyperSpec에 따르면 :

"labels은 과 동일하지만 레이블의 정의 된 함수 이름의 범위는 본문뿐만 아니라 함수 정의 자체도 포함합니다."

다음은 로컬로 정의 된 f가 이상 종료 방법을 보여주는, 모두가 좋아하는 장난감 폐쇄 예제 자신의 바인딩 : 카운터의 새로운 값, 그리고 자신이이 두 값을 반환 폐쇄를 반환

(defun make-counter (n) 
    (labels ((f() (values (incf n) (function f)))) 
    (function f))) 

함수 값. 예제 사용 :

클로저를 반환하는 대신 데이터 구조에 저장하는 것이 중요합니다.

+0

완벽한! (편집 된 질문의 결과를 참조하십시오.) 감사합니다! –

+0

도움이 되니 기쁩니다! –

+1

@Bill : Related (but not duplicate) : http://stackoverflow.com/q/7936024/13, 이는 왜 'labels'또는 'letrec'또는 Y 결합 자 등이 필요한지를 설명합니다. (공개 : 대답을 썼다.) –