2009-02-24 5 views
53

Jamie Zawinski 당신이 무슨 뜻인지 알고 있어야하는 것처럼 자신의 (1997) article "java sucks"의 용어 사용 : 정말 아래쪽 funargs의 부족을 싫어"아래쪽 funargs"무엇입니까?

을; 익명 클래스는 절름발이 대체품입니다. (I는 수명이 긴 폐쇄 없이는 살 수 있지만 기능의 부족이 큰 고통을 포인터 찾을 수 있습니다.)

Lisper의 속어 것 같다, 내가 찾을 수있는 간단한 정의 here하지만, 어떻게 든, 내가 생각하는 다음 나는 여전히 그것을 얻지 못한다 :

많은 클로저는 그들이 참조하는 바인딩 범위 내에서만 사용된다. 이것들은 Lisp 말로 "하향 funargs"로 알려져 있습니다.

내가 지금 바보가 된 기분 것, Steve Yegge 그것을 아니었지만, 물어 OK 수 있습니다 보인다 :

제이미 자윈 스키 영웅이다. 살아있는 전설. [...] "아래쪽 funargs"라는 용어를 사용하고 그 다음에 당신을 대담하게 보며 당신이 그걸 설명해달라고 부탁 할 수있는 사람, 당신은 흠뻑 젖어 있습니다.

-XEmacs is dead, long live XEmacs

그래서 나 같은 C 스타일의 프로그래머가이 컴파일 할 수 있습니다 여기에 Lisper가?

+1

나는 funargs가 java에서 지원되지 않는다는 것을 이해할 수 있지만, 아래쪽 funargs는 닫혀있는 변수의 일반적인 스택 기반 저장소에 대한 변경없이 지원되었을 수 있다는 것을 의미하는 jwz는 무엇을 의미한다고 생각합니다. "Funarg_problem"에 대한 위키피디아 페이지는 실제로 이것에 대해 매우 분명합니다. –

답변

50

아래쪽 Funargs는 반환되지 않거나 선언 범위를 벗어나는 로컬 함수입니다. 그것들은 아래쪽을 현재 범위의 다른 기능들로 전달할 수 있습니다.

두 가지 예입니다. 이 아니지만

function() { 
    var a = 42; 
    var f = function() { return a + 1; } 
    foo(f); // `foo` is a function declared somewhere else. 
} 

:

CL 로의
function() { 
    var a = 42; 
    var f = function() { return a + 1; } 
    return f; 
} 
+0

첫 번째 예제는 var foo = function ...이라고 말해야합니다. –

+0

Christian : 음, 첫 번째는'foo'가 * anywhere *로 정의 된 함수이며 반드시 로컬이 아니라는 것을 의미합니다. 나는 이것을 분명히 할 것이다. –

+7

주요 점은 f가 실행될 때 스택에 a가 있으므로 다른 곳에서 저장할 필요가 없다는 것입니다 (일반적으로 소위 클로저의 힙에 f와 함께). 그래서 "아래로 funarg"은 "funarg"의 쉬운 부분입니다. – starblue

11

Funarg problem

는 "A 아래 funarg도 에 그 기능 실제로, 그러나. 을 실행하지 않는 기능의 상태를 참조 할 수있다라는 위키에 꽤 설명 글이있다, 정의에 의해, 존재하기 때문에 에 에 의 하위 실행 코드가 포함되어 있으면 에 대한 활성화 기록은 보통 이 스택에 저장 될 수 있습니다. "

13

:

(let ((a 3)) 
    (mapcar (lambda (b) (+ a b)) 
      (list 1 2 3 4))) 

-> (4 5 6 7) 

은 상기 형태에서 람다 함수 하향 전달이 하향 funarg이다. 고차 함수 MAPCAR (함수와 값 목록을 인수로 얻은 다음 함수를 목록의 각 요소에 적용하고 결과 목록을 반환)에 의해 호출되면 람다 함수는 여전히 변수를 참조합니다 LET 표현식에서 'a'. 그러나 그것은 LET 표현 내에서 모두 발생합니다.

이 버전과 상기 비교 :

(mapcar (let ((a 3)) 
      (lambda (b) (+ a b))) 
     (list 1 2 3 4)) 

여기서 람다 함수 LET에서 반환된다. 약간 UP. 그런 다음 MAPCAR로 전달됩니다. MAPCAR이 람다 함수를 호출 할 때, 그 주변의 LET은 더 이상 실행되지 않습니다 - 여전히 함수는 변수 'a'를 LET에서 참조해야합니다.

24

용어의 출처를 더 잘 이해하려면 몇 가지 기록을 알아야합니다.

오래된 리스프 해커가 일반적으로 funargs에서 아래로 funargs을 구별 할 수 이유는 일반적인 경우가 어려운 반면, 하향 funargs는, 어휘 변수가 부족 전통적인 리스프에서 쉽게 구현할 수 있다는 것입니다.

전통적 로컬 변수 환경에 바인딩 (그것의 값과 쌍 변수의 심볼 명 등)를 추가하여 리스프 인터프리터 구현되었다. 이러한 환경은 연관 목록을 사용하여 구현하기가 간단했습니다. 각 함수에는 고유 한 환경이 있고 부모 함수의 환경에 대한 포인터가 있습니다. 변수 참조는 현재 환경을 살펴보고 거기에 없으면 상위 환경에서 해결되고 전역 환경에 도달 할 때까지 환경 스택을 정리합니다.

이러한 구현에서 로컬 변수 그림자 같은 이름을 가진 전역 변수. 예를 들어, Emacs Lisp에서 print-length은 약어를 인쇄하기 전에 인쇄 할 최대 길이를 지정하는 전역 변수입니다. 함수에 대한 호출 주위에이 변수를 바인딩하여 해당 함수 내에서 print 문의 동작을 변경할 수 있습니다

 
(defun foo() (print '(1 2 3 4 5 6))) ; output depends on the value of print-length 

(foo) ; use global value of print-length 
    ==> (1 2 3 4 5 6) 

(let ((print-length 3)) (foo)) ; bind print-length locally around the call to foo. 
    ==> (1 2 3 ...) 

당신은 이러한 구현에 그것을 볼 수 아래 funargs 변수 때문에 구현하기가 정말 쉽다 함수가 생성 될 때 함수의 환경에있는 함수는 평가 될 때 함수의 환경에있게됩니다. 이처럼 행동

변수 특별 또는 동적 변수라고하며, 당신은 special 선언을 사용하여 커먼 리스프에서 그들을 만들 수 있습니다.