게으른 평가

Lazy evaluation

프로그래밍 언어 이론에서 게으른 평가(call-by-need)[1]표현식의 평가를 그 값이 필요할 때까지 지연시키고(비엄격한 평가), 반복적인 평가(공유)[2][3]회피하는 평가 전략입니다.

게으른 평가의 이점은 다음과 같습니다.

  • 제어 흐름(구조)을 원시값이 아닌 추상화로 정의하는 기능.
  • 잠재적인 무한 데이터 구조정의하는 기능.이를 통해 일부 알고리즘을 보다 쉽게 구현할 수 있습니다.
  • 일부 요소가 오류인 경우 부분적으로 정의된 데이터 구조를 정의할 수 있습니다.이를 통해 신속한 시제품을 제작할 수 있습니다.

Jon Bentley의 "Writing Efficient Programs"[4]에서 설명한 바와 같이 게으른 평가는 메모화와 결합되는 경우가 많습니다.해당 파라미터 또는 파라미터 세트에 대한 함수 값이 계산되면 결과는 이들 파라미터 값에 의해 인덱스된 룩업테이블에 저장됩니다.다음으로 함수를 호출할 때 테이블을 참조하여 파라미터 값의 조합에 대한 결과가 이미 사용 가능한지 여부를 판단합니다.이 경우 저장된 결과가 단순하게 반환됩니다.그렇지 않으면 함수가 평가되고 재사용을 위해 다른 엔트리가 룩업테이블에 추가됩니다.

느린 평가는 작업 순서가 불확실해지기 때문에 예외 처리 및 입출력 등의 필수 기능과 결합하기가 어렵습니다.

게으른 평가의 반대는 때로는 엄격한 평가로 알려진 열정적인 평가이다.열성적인 평가는 대부분의 프로그래밍 언어에서 사용되는[quantify] 평가 전략입니다.

역사

느린 평가는 Christopher Wadsworth에[5] 의해 람다 미적분에 도입되어 Plesey System 250에 의해 Lambda-Calculus Meta-Machine의 중요한 부분으로 채택되어 용량 제한이 있는 주소 [6]공간에서 객체에 액세스하기 위한 분해능 오버헤드를 줄였다.프로그래밍 언어의 경우 Peter Henderson과 James H. Morris와 Daniel P.[7] 의해 독립적으로 도입되었습니다. 프리드먼과 데이비드 S.현명하다.[8][9]

적용들

지연 평가는 특히 기능 프로그래밍 언어에서 사용됩니다.지연된 평가를 사용하는 경우 표현식은 변수에 바인딩되는 즉시 평가되지 않고 평가자가 표현식의 값을 생성하도록 강요될 때 평가됩니다.즉, 다음과 같은 진술입니다.x = expression;(즉, 표현식의 결과를 변수에 할당하는 것) 표현식의 평가와 그 결과를 명확히 요구한다.x하지만 실제의 내용은x에 대한 참조를 통해 그 가치를 필요로 할 때까지 무관하다.x평가 자체가 연기될 수 있는 일부 후기 표현에서, 비록 결국 빠르게 성장하는 종속성 트리가 외부 세계가 [10]볼 수 있는 다른 것보다 어떤 기호를 생성하기 위해 제거될 것이다.

제어 구조

느린 평가를 통해 제어 구조를 원시 또는 컴파일 시간 기법으로 정의하지 않고 정상적으로 정의할 수 있습니다.예를 들어 if-then-else단락 평가 [11][12]연산자를 정의할 수 있습니다.

If Then Else 진실의 b c = b If Then Else 거짓의 b c = c  --또는 진실의    b = 진실의 거짓의    b = b  --그리고 진실의 & & b = b 거짓의 & & b = 거짓의 

이것들은 일반적인 의미론이다.ifThenElse a b c(a)를 평가한 후 (a)가 참으로 평가한 경우에만 (b)를 평가하며, 그렇지 않으면 (c)를 평가합니다.즉, 정확히 (b) 또는 (c) 중 하나가 평가됩니다.마찬가지로EasilyComputed LotsOfWork쉬운 부분이 True를 준다면 많은 업무 표현을 피할 수 있다.마지막으로 평가 시SafeToTry && ExpressionSafeToTry가 false경우 식을 평가하지 않습니다.

반대로, 열정적인 언어로 위의 정의는ifThenElse a b c(a), (b) 및 (c)는 (a)의 값에 관계없이 평가합니다.이는 (b) 또는 (c)에 부작용이 있거나 계산 시간이 오래 걸리거나 오류가 발생할 수 있으므로 바람직한 동작이 아닙니다.신속한 평가를 위해 언어의 구문에서 이탈할 수 있지만, 일반적으로 사용자 정의의 게으른 제어 구조를 함수로 도입할 수 있습니다.많은 경우 관련 코드 본문은 함수 값으로 감싸야 하기 때문에 호출 시에만 실행됩니다.

무한 확장 데이터 구조 사용

지연평가는 무한루프나 계산에 방해가 되는 크기 문제 없이 계산 가능한 무한목록을 작성할 수 있다는 장점이 있습니다.실제 값은 필요할 때만 계산됩니다.예를 들어, 피보나치 번호의 무한 리스트(흔히 스트림이라고 불린다)를 작성하는 함수를 작성할 수 있습니다.n번째 피보나치 수 계산은 무한 목록에서 해당 요소를 추출하는 것일 뿐이며 목록의 [13][14]첫 번째 n개 멤버만 평가해야 합니다.

Haskell의 간단한 프로그램을 예로 들어 보겠습니다.

number From Infinite List :: 내부 -> 내부 number From Infinite List n =  무궁무한 !! n - 1     어디에 무궁무한 = [1..]  주된 = 인쇄물 $ number From Infinite List 4 

함수에서numberFromInfiniteList 값은 무한 범위이지만 실제 값(구체적으로는 특정 인덱스의 특정 값)이 필요할 때까지 목록은 평가되지 않으며 필요한 경우에만 평가됩니다(즉, 원하는 인덱스가 될 때까지).프로그래머가 주의를 기울이면 프로그램은 정상적으로 완료됩니다.단, 특정 계산에 의해 프로그램이 무한한 수의 요소를 평가하려고 할 수 있습니다.예를 들어 리스트의 길이를 요구하거나 폴드 조작으로 리스트의 요소를 합산하려고 하면 프로그램이 종료되지 않거나 메모리가 부족하게 됩니다.

다른 예로 모든 피보나치 번호 목록을 Haskell 프로그래밍 언어로 다음과 [14]같이 작성할 수 있습니다.

 파이브 = 0 : 1 : zip With (+) 파이브 (꼬리 파이브) 

Haskell 구문에서 ":목록에 요소를 추가합니다.tail첫 번째 요소가 없는 목록을 반환합니다.zipWith는 지정된 함수(이 경우 추가)를 사용하여 두 목록의 대응하는 요소를 결합하여 세 번째 [13]함수를 생성합니다.

성공 목록 패턴

기타 용도

컴퓨터 윈도우 시스템에서 화면으로의 정보 도색은 가능한 마지막 순간에 표시 코드를 구동하는 노출 이벤트에 의해 구동된다.이것에 의해, 윈도우 시스템은 불필요한 디스플레이 컨텐츠의 [15]갱신을 회피할 수 있습니다.

현대 컴퓨터 시스템의 게으름의 또 다른 예로는 Copy-on-Write 페이지 할당 또는 요구 페이징이 있습니다.이 경우 메모리에 저장된 값이 [15]변경되었을 때만 메모리가 할당됩니다.

게으름은 고성능 시나리오에서 유용합니다.예를 들어 Unix mmap 함수는 디스크에서 페이지를 디맨드 방식으로 로드하기 때문에 실제로 터치된 페이지만 메모리에 로드되고 불필요한 메모리는 할당되지 않습니다.

MATLABCopy on Edit을 구현합니다.이 경우 복사된 어레이의 내용이 변경되었을 때만 실제 메모리 스토리지가 복제되므로 복사 [16]작업 중 대신 나중에 요소를 업데이트할 때 메모리 부족 오류가 발생할 수 있습니다.

성능

니즈별 호출이 있는 람다 항을 줄이기 위한 베타 감소 수는 값별 호출 또는 이름별 호출 [17][18]감소에 필요한 개수보다 크지 않습니다.또한 특정 프로그램에서는 단계 수가 훨씬 적을 수 있습니다. 예를 들어 교회 숫자를 사용하는 람다 용어 패밀리는 값별 호출(즉, 완료하지 않음), 이름별 호출이 있는 기하급수적인 단계 수, 니즈별 호출이 있는 다항식 숫자만 사용하여 무한히 많은 단계를 수행합니다.Call-by-Need는 두 가지 최적화를 구현합니다. 즉, 반복 작업(값별 콜과 유사)과 불필요한 작업([19]이름별 콜과 유사)을 수행하지 않습니다.또한 필요할 [20]때 값이 생성되므로 느린 평가를 통해 메모리 사용 공간을 줄일 수도 있습니다.

실제로, 느린 평가는 열성적인 평가에 비해 심각한 성능 문제를 일으킬 수 있습니다.예를 들어, 현대의 컴퓨터 아키텍처에서는 계산을 지연시키고 나중에 수행하는 것이 즉시 수행하는 것보다 느립니다.는 엄격도 [19]분석을 통해 완화될 수 있습니다.또, 느긋한 평가를 실시하면,[21][22] 표현에 의한 메모리 누수가 발생할 가능성이 있습니다.

실행

일부 프로그래밍 언어는 기본적으로 식 평가를 지연시키고 일부 프로그래밍 언어는 함수를 제공하거나 특별한 구문을 제공하여 평가를 지연시킵니다.미란다와 해스켈에서는 함수 인수의 평가가 기본적으로 지연됩니다.다른 많은 언어에서는 특별한 구문을 사용하여 계산을 명시적으로 중단함으로써 평가가 지연될 수 있습니다(Scheme의 " "와 같이).delay" 및 "force" 및 OCaml의 "lazy" 및 "Lazy.force ") 또는 더 일반적으로는 퉁크로 표현합니다.이렇게 명시적으로 지연된 평가를 나타내는 개체를 게으른 미래라고 합니다.라쿠는 리스트에 대한 느린 평가를 사용하기 때문에 변수에 무한 리스트를 할당해 함수에 대한 인수로 사용할 수 있지만,[10] 하스켈이나 미란다와 달리 기본적으로는 산술 연산자와 함수에 대한 느린 평가를 사용하지 않는다.

게으름과 열심

게으른 언어로 열정을 억제하다

Haskell과 같은 느린 프로그래밍 언어에서는 기본적으로 식이 요구되었을 때만 식을 평가하지만, 경우에 따라서는 코드를 더 빠르게 만들거나 더 열심히 만든 후에 다시 게으르게 만들 수도 있습니다.이것은, 평가를 강제하는 것을 명시적으로 코드화하거나(코드가 보다 열심인 경우가 있다), 또는 그러한 코드를 회피하는 것으로 실시할 수 있습니다(코드가 보다 게으를 가능성이 있다).엄격한 평가는 보통 열의를 의미하지만, 그것들은 엄밀히 말하면 다른 개념이다.

그러나, 일부 컴파일러에서는 엄격도 분석이라고 불리는 최적화가 구현되어 있으며, 이것은 어떤 경우에 컴파일러가 값이 항상 사용될 것이라고 추론할 수 있게 한다.이러한 경우, 엄밀성 분석은 엄격한 평가를 강요하기 때문에 프로그래머의 특정 값 강제 여부 선택은 무관할 수 있습니다.

Haskell에서 생성자 필드를 strict로 표시하면 해당 값이 항상 즉시 요구됩니다.seq함수는 값을 즉시 요구한 후 전달하기 위해 사용할 수도 있습니다.이것은 컨스트럭터 필드가 일반적으로 게으른 경우에 유용합니다.단, 이러한 기술 중 어느 것도 재귀적 엄격성을 구현하지 않습니다.이러한 경우,deepSeq발명되었습니다.

또한 Haskell 98의 패턴 매칭은 기본적으로 엄격하기 때문에~수식자를 사용하여 [23]게으르게 만들어야 합니다.

열심히 하는 언어로 게으름을 흉내내다

자바

Java에서는 값이 필요할 때 평가하는 메서드가 있는 개체를 사용하여 느린 평가를 수행할 수 있습니다.이 메서드의 본문에는 이 평가를 수행하는 데 필요한 코드가 포함되어 있어야 합니다.Java SE8에서 람다 표현식이 도입된 이후 Java는 이를 위한 콤팩트 표기법을 지원했습니다.다음 범용 인터페이스 [24][25]에서는 지연 평가용 프레임워크를 제공하고 있습니다.

인터페이스 게으른< >T> {     T 평가하다(); } 

Lazy그것의 인터페이스eval()메서드는 다음과 같습니다.Supplier그것의 인터페이스get()의 메서드java.util.function라이브러리로 이동합니다.[26]

가 실장하는 각 클래스Lazy인터페이스에서는, 다음의 정보를 제공할 필요가 있습니다.eval메서드 및 클래스의 인스턴스는 메서드가 느린 평가를 수행하는 데 필요한 모든 값을 전달할 수 있습니다.예를 들어, 다음 코드를 고려하여 계산과 인쇄를10 게을리 합니다2 .

게으른< >정수> a = ()-> 1; 위해서 (인트 i = 1; i <=> 10; i++) {     최종 게으른< >정수> b = a;     a = ()-> b.평가하다() + b.평가하다(); } 시스템..나가..인쇄( "a =" + a.평가하다() ); 

위에서 변수 a는 처음에 람다 식에 의해 생성된 느린 정수 개체를 참조합니다.()->1이 람다 식을 평가하는 것은 를 구현하는 어나니머스 클래스의 새 인스턴스를 구축하는 것과 같습니다.Lazy<Integer>eval 메서드가 1을 반환하는 경우.

루프를 반복할 때마다 루프 내의 람다 식을 평가하여 작성된 새로운 객체에 가 링크됩니다.이들 오브젝트 각각은 다른 레이지 오브젝트 b에 대한 참조를 보유하고 있으며 콜하는 평가 메서드가 있습니다.b.eval()합계를 반환한다.여기서 변수 b는 람다 식 내에서 참조되는 변수가 최종 변수여야 한다는 Java의 요구사항을 충족하기 위해 필요합니다.

이것은 비효율적인 프로그램입니다.이러한 정수의 실장에서는 이전에 평가한 콜의 결과가 메모되지 않기 때문입니다.또한 상당한 자동 박스와 언박스를 수반합니다.명확하지 않을 수 있는 것은, 루프의 마지막에, 프로그램이 11개의 오브젝트의 링크 리스트를 작성하고, 그 결과를 계산하기 위한 실제의 모든 추가가, 다음의 호출에 응답해 행해진다는 것입니다.a.eval()암호의 마지막 줄에 있습니다.이 콜은 목록을 재귀적으로 통과하여 필요한 추가를 수행합니다.

다음과 [24][25]같이 지연 개체를 메모하는 Java 클래스를 만들 수 있습니다.

학급 메모< >T> 용구 게으른< >T> {     사적인 게으른< >T> 게으른;  // 느린 표현식, eval이 null로 설정합니다.     사적인 T 메모 = 무효; // 이전 값의 각서      일반의 메모( 게으른< >T> 게으른 ) { // 컨스트럭터         이것..게으른 = 게으른;     }      일반의 T 평가하다() {         한다면 (게으른 != 무효) {             메모 = 게으른.평가하다();             게으른 = 무효;         }         돌아가다 메모;     } } 

이를 통해 이전 예를 훨씬 더 효율적으로 다시 작성할 수 있습니다.원래 실행 시간이 반복 횟수로 지수인 경우 메모된 버전은 선형 시간으로 실행됩니다.

게으른< >정수> a = ()-> 1; 위해서 (인트 i = 1; i <=> 10; i++) {     최종 게으른< >정수> b = a;     a = 신규 메모< >정수>( ()-> b.평가하다() + b.평가하다() ); } 시스템..나가..인쇄( "a =" + a.평가하다() ); 

Java의 람다 표현은 통사적인 설탕일 뿐입니다.lamda 식을 사용하여 쓸 수 있는 것은 인터페이스를 구현하는 어나니머스 내부 클래스의 인스턴스를 구축하기 위한 콜로서 변경할 수 있습니다.또한 어나니머스 내부 클래스의 사용은 이름 있는 내부 클래스를 사용하여 다시 작성할 수 있습니다.또한 이름 있는 내부 클래스는 가장 바깥쪽 네스트레벨로 이동할 수 있습니다

자바스크립트

JavaScript에서는 생성기를 사용하여 느린 평가를 시뮬레이션할 수 있습니다.예를 들어 메모화를 사용하여 모든 피보나치 번호의 스트림을 다음과 같이 쓸 수 있습니다.

/** * 제너레이터 함수는 제너레이터 개체를 반환하여 느린 평가를 재현합니다. * @return {!생성기 <bigint>} Null이 아닌 정수 생성기. */ 기능.* fibonacciNumbers() {     허락하다 메모 = [1n, -1n]; // 초기 상태 생성(예: "negafibonacci" 번호의 벡터)     하는 동안에 (진실의) { // 무한 반복         메모 = [메모[0] + 메모[1], 메모[0]]; // 각 평가의 상태 업데이트         산출하다 메모[0]; // 다음 값을 지정하고 재개될 때까지 실행을 일시 중지합니다.     } }  허락하다 개울. = fibonacciNumbers(); // 느긋하게 평가된 숫자의 스트림을 만듭니다. 허락하다 첫 번째 10 = 어레이.부터(신규 어레이(10), () => 개울..다음 분.().가치); // 처음 10개의 숫자만 평가 콘솔.로그.(첫 번째 10); // 출력은 [0n, 1n, 1n, 2n, 3n, 5n, 8n, 13n, 21n, 34n] 

파이썬

Python 2.x에서는range()함수는[27] 정수 목록을 계산합니다.첫 번째 할당문이 평가될 때 목록 전체가 메모리에 저장되므로 다음 예시는 긴급 또는 즉시 평가의 예입니다.

>>>r = 범위(10) >>>인쇄물 r [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>>인쇄물 r[3] 3 

Python 3.x에서는range()함수는[28] 요청 시 목록의 요소를 계산하는 생성기를 반환합니다.요소는 필요한 경우에만 생성됩니다(예: 다음과 같은 경우).print(r[3])는 다음 예에서 평가됩니다.따라서 이것은 게으른 평가 또는 지연된 평가의 예입니다.

>>>r = 범위(10) >>>인쇄물(r) 범위(0, 10) >>>인쇄물(r[3]) 3 
이 느린 평가로 변경하면 완전히 참조되지 않을 수 있는 대규모 범위의 실행 시간과 한 번에 1개 또는 몇 개의 요소만 필요한 대규모 범위의 메모리 사용량이 절약됩니다.

Python 2.x 에서는, 라고 하는 함수를 사용할 수 있습니다.xrange()요청 시 범위 내의 숫자를 생성하는 개체를 반환합니다.장점xrange생성된 객체는 항상 같은 양의 메모리를 사용합니다.

>>>r = xrange(10) >>>인쇄물(r) xrange(10) >>>첫 번째 = [x 위해서 x  r] >>>인쇄물(첫 번째) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 

버전 2.2 이후 Python은 튜플 또는 목록 시퀀스와 달리 반복기(Lazy Sequence)를 구현하여 느린 평가를 구현합니다.예: (Python 2)

>>>숫자 = 범위(10) >>>리터레이터 = 반복하다(숫자) >>>인쇄물 숫자 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>>인쇄물 리터레이터 <0µ7e8dd4c의 리스티케이터 오브젝트> >>>인쇄물 리터레이터.다음 분.() 0 
위의 예에서는 호출 시 목록이 평가되지만 반복자의 경우 첫 번째 요소 '0'이 필요할 때 인쇄됩니다.

.NET 프레임워크

에서.NET Framework 클래스를 사용하여 게으른 평가를 수행할 수 있습니다.System.Lazy<T>이 클래스는 F#에서 쉽게 이용할 수 있습니다.[29]lazy키워드를 지정하고,forcemethod는 평가를 강제합니다.다음과 같은 전문 컬렉션도 있습니다.Microsoft.FSharp.Collections.Seq게으른 평가에 대한 기본 지원을 제공합니다.

허락하다 파이보나치 = .펼치다 (재밌어요 (x, y) -> 몇개(x, (y, x + y))) (0I,1 I) 파이보나치 > .n번째 1000 

C# 및 VB의 경우.NET, 클래스System.Lazy<T>는 직접 사용됩니다.

일반의 인트 () {     인트 a = 0;     인트 b = 0;      게으른< >인트> x = 신규 게으른< >인트>( ) => a + b);     a = 3;     b = 5;     돌아가다 x.가치; // 8을 반환합니다. } 

또는 보다 실용적인 예를 들 수 있습니다.

// n번째 피보나치 번호의 재귀 계산 일반의 인트 파이브(인트 n) {    돌아가다 (n == 1)? 1 : (n == 2)? 1 : 파이브(n-1) + 파이브(n-2); }  일반의 무효 주된() {     콘솔.기입선("어떤 피보나치 숫자를 계산하시겠습니까?");     인트 n = Int32.해석(콘솔.라인 읽기());      게으른< >인트> 파이브 = 신규 게으른< >인트>( ) => 파이브(n)); // 함수는 준비되었지만 실행되지 않음     부울 실행하다;      한다면 (n > 100)     {         콘솔.기입선(시간이 좀 걸릴 수 있습니다.이 큰 숫자를 계산하시겠습니까?[y/n]);         실행하다 = (콘솔.라인 읽기() == "y");      }     또 다른 실행하다 = 진실의;          한다면 (실행하다) 콘솔.기입선(파이브.가치); // 숫자는 필요한 경우에만 계산됩니다. } 

또 다른 방법으로는yield키워드:

// 열성적인 평가 일반의 IENumerable< >인트> 피보나치(인트 x) {     리스트< >인트> 파이브 = 신규 목록.< >인트> ( ) ;      인트 프리브 = -1;     인트 다음 분. = 1;     위해서 (인트 i = 0; i < > x; i++)     {         인트  = 프리브 + 다음 분.;         프리브 = 다음 분.;         다음 분. = ;         파이브.더하다();      }     돌아가다 파이브; }  // 느린 평가 일반의 IENumerable< >인트> 레이지 파이보나치(인트 x) {     인트 프리브 = -1;     인트 다음 분. = 1;     위해서 (인트 i = 0; i < > x; i++)     {         인트  = 프리브 + 다음 분.;         프리브 = 다음 분.;         다음 분. = ;         산출하다 돌아가다 ;     } } 

「 」를 참조해 주세요.

레퍼런스

  1. ^ 후닥 1989, 384페이지
  2. ^ David Anthony Watt; William Findlay (2004). Programming language design concepts. John Wiley and Sons. pp. 367–368. ISBN 978-0-470-85320-7. Retrieved 30 December 2010.
  3. ^ 레이놀즈 1998, 페이지 307
  4. ^ 벤틀리, 존 루이스효율적인 프로그램 작성프렌티스 홀, 1985년ISBN 978-0139702440
  5. ^ 워즈워스 1971
  6. ^ Hamer-Hodges, Kenneth (1 Jan 2020). Civilizing Cyberspace: The Fight for Digital Democracy. p. 410. ISBN 978-1-95-163044-7. Retrieved 29 February 2020.
  7. ^ 헨더슨 & 모리스 1976
  8. ^ 프리드먼 & 와이즈 1976
  9. ^ 레이놀즈 1998, 312페이지
  10. ^ a b Philip Wadler (2006). Functional and logic programming: 8th international symposium, FLOPS 2006, Fuji-Susono, Japan, April 24-26, 2006 : proceedings. Springer. p. 149. ISBN 978-3-540-33438-5. Retrieved 14 January 2011.
  11. ^ "utility-ht: Data.Bool.HT.Private". hackage.haskell.org. Retrieved 8 January 2022.
  12. ^ "The Haskell 98 Report: Standard Prelude". www.haskell.org. Boolean functions. Retrieved 8 January 2022.
  13. ^ a b Daniel Le Métayer (2002). Programming languages and systems: 11th European Symposium on Programming, ESOP 2002, held as part of the Joint European Conferences on Theory and Practice of Software, ETAPS 2002, Grenoble, France, April 8-12, 2002 : proceedings. Springer. pp. 129–132. ISBN 978-3-540-43363-7. Retrieved 14 January 2011.
  14. ^ a b Association for Computing Machinery; ACM Special Interest Group on Programming Languages (1 January 2002). Proceedings of the 2002 ACM SIGPLAN Haskell Workshop (Haskell '02): Pittsburgh, Pennsylvania, USA ; October 3, 2002. Association for Computing Machinery. p. 40. ISBN 978-1-58113-605-0. Retrieved 14 January 2011.
  15. ^ a b 게으르고 투기적실행 버틀러 Lampson 마이크로소프트 리서치 OPODIS, 프랑스 보르도, 2006년 12월 12일
  16. ^ "Out of memory when assigning values to existing arrays? - MATLAB Answers - MATLAB Central".
  17. ^ Niehren, Joachim (1996). "Functional computation as concurrent computation" (PDF). Proceedings of the 23rd ACM SIGPLAN-SIGACT symposium on Principles of programming languages - POPL '96: 333–343. doi:10.1145/237721.237801.
  18. ^ Niehren, Joachim (September 2000). "Uniform confluence in concurrent computation". Journal of Functional Programming. 10 (5): 453–499. doi:10.1017/S0956796800003762. Retrieved 7 January 2022.
  19. ^ a b Stelle, George Widgery (July 2019). Shared-Environment Call-by-Need (PhD). University of New Mexico. pp. 11–12. Retrieved 8 January 2022.
  20. ^ Chris Smith (22 October 2009). Programming F#. O'Reilly Media, Inc. p. 79. ISBN 978-0-596-15364-9. Retrieved 31 December 2010.
  21. ^ Launchbury 1993.
  22. ^ 에드워드 Z양. "우주 누출 동물원"
  23. ^ "Lazy pattern match - HaskellWiki".
  24. ^ a b Grzegorz Piwawarek, Lambda Expressions for Lazy Evaluations in Java, 4Acliption, 2018년 7월 25일
  25. ^ a b DouglasW. 존스 씨 CS:2820 메모, 2020년, 강의 25,1월, 2021년까지 회수된 Fall.
  26. ^ 인터페이스 Suppier<T>, 10월 2020년 돌려받지 못 했다.
  27. ^ "2. Built-in Functions — Python 2.7.11 documentation".
  28. ^ "2. Built-in Functions — Python 3.5.1 documentation".
  29. ^ "Lazy(T) Class (System)". Microsoft.

읽고 추가

외부 링크

  • Nemerle에Lazy 평가 매크로.
  • 부스트 도서관의 C++언어로 람다 결석
  • 게으른 평가 ANSIC++에서 함수 폐쇄를 시행할 클래스를 사용하여 스타일로 코드를 작성.