2014-11-03 2 views
5

우리는 변수에 값 할당하는 경우 : 다음캡처 값

(setf i 10) 

및 위에 람다 함수를 폐쇄 만들 : 우리는 동작을

(setf f #'(lambda() i)) 

(incf i) ;=> 11 
(funcall f) ;=> 11 

대신, 나는 함수가 항상 그 시간에 i의 값을 반환하고 싶습니다 만들었습니다. 예컨대 :

(incf i) ;=> 11 
(funcall f) ;=> 10 

는 기본적으로 내가 람다 본체 내부에 문자로 i을 설정하고 싶습니다. 이것은 Common Lisp에서 할 수 있습니까? 그 이유는 하나의 루프 안에 하나 이상의 람다를 만들고, 생성 후에 변화하지 않고 그들의 몸에 인덱스를 사용해야하기 때문입니다.

+3

I DOLIST 예를 들어 다음 중 하나로 정의 할 수 있습니다 '잠깐 '에 대해 조금 읽으라고 제안한다. –

답변

8

변수를 값의 복사본으로 바인딩하면됩니다. 예 :

(let ((i i)) 
    (lambda() i)) 

뭔가

(loop for i from 1 to 10 
    collecting (lambda() i)) 

처럼이 같은 변수를 통해 열 클로저를 반환 할 수 있기 때문, 실제로 반복 구조와 중요한 기술이다, 그래서 쓰기 할 필요가 :

(loop for i from 1 to 10 
    collecting (let ((i i)) (lambda() i))) 

값을 반환하는 함수가 실제로 필요한 경우 constantly을 사용할 수도 있습니다 (하지만 실제 사용 사례는 더 복잡 할 것으로 예상합니다) :

(loop for i from 1 to 10 
    collecting (constantly i)) 

경우에 따라 반복 형식의 모호성이 실제로 표준에 의해 지정됩니다. 예를 들어, dotimes를 들어, dolist

이 dotimes이 반복 될 때마다 VAR의 새로운 바인딩을 설정 여부 구현에 의존하거나 여부를 초기에 한 번 var에 바인딩을 설정 한 후 후속 반복에 할당합니다.

더 원시적 do 그러나 실제로이 폼 바인딩 한 세트이며, 그들은 각각의 반복으로 업데이트되도록 (강조 추가)하도록 지정 각각의 시작 부분에서

첫 번째 반복 이외의 반복은 다음과 같이 으로 업데이트합니다.& hellip;

이 애매한 점은 구현에 약간의 유연성을 제공합니다. 위의 두 답변 선명도 충분하지 않습니다 이런 경우에

(defmacro dolist ((var list &optional result) &body body) 
    `(progn (mapcar #'(lambda (,var) 
         ,@(ex:body-declarations body) 
         (tagbody 
         ,@(ex:body-tags-and-statements body))) 
        ,list) 
      (let ((,var nil)) 
      ,result))) 

(defmacro dolist ((var list &optional result) &body body) 
    (let ((l (gensym (string '#:list-)))) 
    `(do* ((,l ,list (rest ,l)) 
      (,var (first ,l) (first ,l))) 
      ((endp ,l) ,result) 
     ,@body))) 
+0

해결! 두 번째 예제에서와 같이 반복 구조를 수행하고 마지막 인덱스의 값으로 모든 클로저를 가져 오는 중입니다. 고마워요 조슈아! –

+0

@DiogoFranco 예, 몇 가지 반복 구문에 몇 개의 바인딩 양식이 있는지 몇 가지 고의적 인 모호성 (구현에 의존하는 동작)이 있습니다. 이유를 설명하기 위해 내 답변에 조금 더 추가했습니다. –

4

여기에서 원하는 내용이 완전히 명확하지 않습니다. 공유 변수 i이있는 범위를 만들려면 let을 사용하면됩니다.

CL-USER> (let ((i 10)) 
     (defun show-i() i) 
     (defun inc-i() (incf i)) 
     (defun dec-i() (decf i))) 
DEC-I 
CL-USER> (show-i) 
10 
CL-USER> (inc-i) 
11 
CL-USER> (show-i) 
11 
CL-USER> (dec-i) 
10 
CL-USER> (dec-i) 
9 
CL-USER> (show-i) 
9 
CL-USER> 

동적 범위 변수를 사용하려는 경우 바로 defvar을 사용할 수 있습니다.

CL-USER> (defvar *a* 10) 
*A* 
CL-USER> (defun show-a() *a*) 
SHOW-A 
CL-USER> (show-a) 
10 
CL-USER> *a* 
10 
CL-USER> (incf *a*) 
11 
CL-USER> (incf *a*) 
12 
CL-USER> (show-a) 
12 
CL-USER> 
+0

오, 그렇지만 나는 그 반대입니다. 위의 예제에서 "funcall f"가 "i"에 관계없이 10을 영원히 반환하고 싶습니다. 나는 "i"의 값을 바인딩하려고하는데, 그 함수가 몸체에 만들어 졌을 때. –

+1

@DiogoFranco이 중 첫 번째 방법이 도움이 될 것입니다. 'i'의 로컬 복사본의 범위를 두 번째 함수와 공유하지 마십시오. (외부'i'에서'let'을 초기화하면,'i' 변수가 2 개 있습니다 : 원래의 바깥 쪽과'let'으로 생성 된 개인 복사본). – Leushenko

4

:

(defparameter *i* 10) 
;;Before you modify *i* 
(defvar f (let ((i *i*)) 
       #'(lambda() i))) 
;;Now f will always return 10 
(funcall f) => 10 
(incf *i*) => 11 
(funcall f) => 10 
+0

'* i *'는'defparameter'로 선언되어 전역 적으로 * 특별한 것으로 선언되기 때문에 이것은 실제로 또 다른 혼란의 포인트를 추가합니다. 즉'let ((* i * * i *)) (lambda() * i))'*는 작동하지 않습니다. (그것은 당신이 한 것과 같지 않지만, let 변수가 특별한 변수를 묶는다면 문제가있을 수 있습니다. –