작동하지 않는 설정에서 클로저 구현 문제


18

프로그래밍 언어에서 클로저는 널리 사용되는 기능입니다. Wikipedia의 말 : (강조 광산) :

컴퓨터 과학에서 클로저 (...)는 해당 함수 의 비 로컬 변수에 대한 참조 환경과 함께 제공되는 함수입니다. 클로저를 사용하면 함수가 즉각적인 어휘 범위 밖의 변수에 액세스 할 수 있습니다.

따라서 클로저는 본질적으로 자신의 범위를 벗어난 변수를 사용할 수있는 (익명?) 함수 값입니다. 내 경험상 이는 정의 지점에있는 변수에 액세스 할 수 있음을 의미합니다.

그러나 실제로 개념은 기능적 프로그래밍의 범위를 벗어나는 것으로 보인다. 언어마다 다른 의미론을 구현하며 심지어 opinons와의 전쟁이있는 것 같습니다. 많은 프로그래머들은 클로저가 무엇인지 알지 못하는 것처럼 보이며 익명 함수 이상으로 간주합니다.

또한 클로저를 구현할 때 큰 장애물이있는 것 같습니다. 가장 주목할만한 Java 7은 그것들을 포함시켜야했지만이 기능은 다음 릴리스로 푸시되었습니다.

폐쇄는 왜 그렇게 이해하기 어렵고 이해하기 어렵습니까? 이것은 너무 광범위하고 모호한 질문이므로 다음과 같은 상호 연결된 질문에 초점을 맞추겠습니다.

  • 일반적인 의미 론적 형식주의 (작은 단계, 큰 단계 등)에서 클로저를 표현하는 데 문제가 있습니까?
  • 기존 유형 시스템은 폐쇄에 적합하지 않으며 쉽게 확장 할 수 없습니까?
  • 전통적인 스택 기반 프로 시저 변환에 따라 클로저를 가져 오는 것이 문제가됩니까?

이 질문은 일반적으로 절차 적, 객체 지향 및 스크립팅 언어와 관련이 있습니다. 내가 아는 한 기능 언어에는 아무런 문제가 없습니다.


좋은 질문. 스칼라에서 클로저가 구현되었고 Martin Odersky가 Java 1.5 컴파일러를 작성 했으므로 왜 Java 7에 없는지 명확하지 않습니다. C #에 있습니다. (나중에 더 나은 답변을 쓰려고 노력할 것입니다.)
Dave Clarke

4
Lisp 및 ML과 같은 불완전한 기능 언어는 클로저를 잘 수용하므로 문제가되는 본질적 의미 론적 이유는 없습니다.
Gilles 'SO- 악의를 멈추십시오'8:12의

작은 단계 의미가 클로저에 대해 어떻게 보일지 상상하기 위해 고군분투했기 때문에 항목을 포함했습니다. 클로저 자체는 문제가되지 않지만,이를 염두에두고 설계되지 않은 언어로 포함시키는 것은 어려운 일입니다.
Raphael

1
pdfs.semanticscholar.org/73a2/…를 살펴보십시오. -Lua의 저자는 그것을 매우 영리하게 만들었으며 클로저 구현의 일반적인 문제에 대해서도 논의했습니다
Bulat

답변:


10

나는 당신을 지시 할 수 Funarg 문제 위키 피 디아 페이지 ? 적어도 이것은 컴파일러 사람들이 클로저 구현 문제를 참조하는 데 사용한 방법입니다.

따라서 클로저는 본질적으로 자신의 범위를 벗어난 변수를 사용할 수있는 (익명?) 함수 값입니다. 내 경험상 이는 정의 지점에있는 변수에 액세스 할 수 있음을 의미합니다.

이 정의는 의미가 있지만, 전통적인 런타임 스택 기반 언어로 일류 함수를 구현하는 문제를 설명하는 데 도움이되지 않습니다. 구현 문제와 관련하여 퍼스트 클래스 함수는 크게 두 가지 클래스로 나눌 수 있습니다.

  • 함수의 지역 변수는 함수가 반환 된 후에는 사용되지 않습니다.
  • 함수가 반환 된 후 지역 변수를 사용할 수 있습니다.

첫 번째 경우 (아래로 funargs)는 구현하기 어렵지 않으며 Algol, C 및 Pascal과 같은 이전 절차 언어에서도 찾을 수 있습니다. C 함수는 중첩 함수를 허용하지 않지만 Algol과 Pascal은 내부 함수가 외부 함수의 스택 변수를 참조 할 수 있도록 필요한 부기를 수행합니다.

반면에 두 번째 경우 (위쪽의 funargs)에는 스택 외부의 힙에 활성화 레코드를 저장해야합니다. 즉, 언어 런타임에 가비지 수집기가 포함되어 있지 않으면 메모리 리소스를 유출하기가 매우 쉽습니다. 오늘날 거의 모든 것이 가비지 수집되지만, 하나를 요구하는 것은 여전히 ​​중요한 설계 결정이며 훨씬 더 오래 전에 이루어졌습니다.


Java의 특정 예제와 관련하여 올바르게 기억한다면 주요 문제는 실제로 클로저를 구현할 수 없지만 익명의 내부 클래스와 같은 기존 기능과 중복되지 않는 방식으로 언어를 소개하는 방법이었습니다. 기존 기능과 충돌하지 않았습니다 (확인 된 예외-해결하기가 쉽지 않고 대부분의 사람들이 처음에는 생각하지 않는 문제).

또한 this , self 또는 super 와 같은 "매직"변수로 수행 할 작업 결정 및 중단반환 과 같은 기존 제어 흐름 연산자와 상호 작용하는 방법 등 일등 함수를 구현하기에 덜 사소한 다른 것들도 생각할 수 있습니다. (로컬이 아닌 반품을 허용 하시겠습니까?) 그러나 결국, 일류 함수의 최근 인기는 그것들을 갖지 않는 언어는 대부분 역사적 이유로 또는 초기에 중요한 디자인 결정으로 인해 그렇게하는 것으로 나타납니다.


1
상향 및 하향 대 / 소문자를 구분하는 언어가 있습니까? .NET 언어에서 하향 전용 함수를받을 것으로 예상되는 일반 메서드는 byref (C #에서는 " ref매개 변수") 와 같은 구조를받는 대리자와 함께 일반 형식의 구조를받을 수 있습니다. 호출자가 구조에서 관심있는 모든 변수를 캡슐화하면 대리자가 완전히 정적 일 수 있으므로 힙 할당이 필요하지 않습니다. 컴파일러는 이러한 구문에 대해 유용한 구문 도움말을 제공하지 않지만 프레임 워크가이를 지원할 수 있습니다.
supercat

2
@supercat : Rust에는 내부 함수가 힙을 사용해야하는 경우 컴파일 타임에 적용 할 수있는 다중 클로저 유형 이 있습니다. 그러나 이것이 모든 추가 유형에 신경 쓰지 않고 구현이 힙 할당을 피하려고 시도 할 수 없다는 것을 의미하지는 않습니다. 컴파일러는 엄격하게 필요한 경우에만 힙에 변수를 지연 저장하기 위해 함수 수명을 유추하거나 런타임 검사를 사용할 수 있습니다 ( 자세한 내용 은 Evolution of Lua 페이퍼 의 "어휘 범위"섹션 참조)
hugomg

5

C #에서 클로저가 어떻게 구현되는지 살펴볼 수 있습니다. C # 컴파일러가 수행하는 변환의 규모는 클로저 구현 방식이 상당히 많은 작업임을 분명히 보여줍니다. 클로저를 구현하는 더 쉬운 방법이있을 수 있지만 C # 컴파일러 팀이 이것을 알고 있다고 생각합니다.

다음 의사 C #을 고려하십시오 (C # 관련 내용을 약간 잘라 냈습니다).

int x = 1;
function f = function() { x++; };
for (int i = 1; i < 10; i++) {
    f();
}
print x; // Should print 9

컴파일러는 이것을 다음과 같이 변환합니다.

class FunctionStuff {
   int x;
   void theFunction() {
       x++;
   }
}

FunctionStuff theClosureObject = new FunctionStuff();
theClosureObject.x = 1;
for (int i = 1; i < 10; i++) {
    theClosureObject.theFunction();
}
print theClosureObject.x; // Should print 9

(실제로 f는 여전히 'delegate'(= 함수 포인터) 인 변수 f가 만들어 지지만이 대리자는 여전히 theClosureObject 객체와 연결되어 있습니다. 익숙하지 않은 사람들을 위해 명확하게하기 위해이 부분을 생략했습니다. C # 사용)

이 변환은 상당히 거대하고 까다 롭습니다. 클로저 내부의 클로저와 나머지 C # 언어 기능과 클로저의 상호 작용을 고려하십시오. Java 7에는 이미 많은 새로운 기능이 있으므로 Java 용 기능이 푸시되었다고 생각할 수 있습니다.


어디로 가는지 알 수 있습니다. 여러 개의 클로저가 있고 주요 범위에 동일한 변수에 액세스하면 혼란 스러울 것입니다.
Raphael

솔직히 말하면 이것은 클로저를 구현하기 위해 기존 OO 프레임 워크를 사용하고 실제 문제가 발생하기 때문입니다. 다른 언어는 변수를 별도의 메서드가없는 구조로 할당 한 다음 원하는 경우 여러 클로저가 공유하도록합니다.
hugomg 2015 년

@Raphael : 클로저 내부 클로저에 대해 어떻게 생각하십니까? 잠시만 기다려주세요.
Alex ten Brink

5

질문의 일부에 답하십시오. Morrisett와 Harper가 기술 한 형식은 클로저를 포함하는 고차 다형성 언어의 큰 단계와 작은 단계 의미를 다룹니다. 이것들 앞에는 원하는 종류의 의미를 제공하는 논문이 있습니다. 예를 들어 SECD machine을보십시오 . 이러한 의미에 가변 참조 또는 가변 로컬을 추가하는 것은 간단합니다. 이러한 의미를 제공하는 데 기술적 인 문제가 있음을 알 수 없습니다.


참조 주셔서 감사합니다! 그것은 가벼운 독서를 위해 보이지는 않지만 의미 론적 논문에서 예상됩니다.
라파엘

1
@Raphael : 아마도 더 간단한 것들이있을 것입니다. 나는 무언가를 찾고 당신에게 돌아올 수 있도록 노력할 것입니다. 어쨌든 그림 8에는 원하는 의미가 있습니다.
Dave Clarke

어쩌면 대략적인 개요를 제공 할 수 있습니다. 답의 중심 아이디어?
Raphael

2
@ 라파엘. 프로그래밍 언어 과정에 사용하는 강의 노트 를 참조 하여 빠르게 소개 할 수 있습니다. 유인물 8과 9를 찾아보십시오.
Uday Reddy

1
해당 링크는 보이지 않거나 인증되지 않은 상태로 나타납니다. ( cs.cmu.edu/afs/cs/user/rwh/public/www/home/papers/gcpoly/tr.pdf ). 403 금지됩니다.
벤 플레처
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.