Lazy Evaluation을 알아보자

Jeongkuk Seo
sjk5766
Published in
4 min readApr 23, 2020

Lazy Evaluation이 무엇이고 장점이 뭔지 살펴 보겠습니다.
* 해석 Tip: Lazy(게으른, 느긋한, 지연된) Evaluation(평가, 연산, 계산)

compiler는 일반적으로 expression(값을 도출하는 코드, ex: 1+3)을 만나면 그 값을 계산(평가)합니다.

Evaluationcompiler가 코드를 보고 최종 결과를 평가하는 과정으로, 예를 들면 code에서 5+3 을 만나면 8로 평가합니다.

대부분의 언어에서 expression을 만나면 즉시 평가 하지만, 항상 효과적인건 아닙니다. 예를 들어 함수가 전달된 파라미터를 사용하지 않는 경우, compiler가 이를 평가할 필요는 없습니다.

def func(x, y):
return x + 1
func(3, 3 + 2)

위 예제에서 3+2는 함수 내부에서 쓰이지 않으므로 평가할 필요가 없습니다.
이 때, 즉시 평가하지 않고, 필요한 것만 평가하는 방법을 lazy evaluation,
즉시 평가하는 방법을 strict evaluation 이라고 부릅니다.

lazy evaluation의 예시 하나를 보겠습니다.

JavaScript는 왼쪽의 a() 호출 결과를 평가하고 값이 false일 경우 필요없는 b는 평가하지 않습니다. 위 처럼 필요없는 평가를 하지 않음으로서 성능의 이득을 취할 수 있습니다.

성능 관점에서 lazy compiler를 좀 더 효율적으로 쓸 수 있는 방법으로 memoization이 있습니다. 한 번 evaluated된 값을 저장하여 재 평가하지 않는 방법으로 dictionary key에는 변수 이름을, value는 평가 결과를 저장하고, 이미 계산된 변수는 재 평가 없이 dictionary에서 바로 사용하여 성능을 향상합니다.

lazy evaluation의 또다른 장점으로 무한 자료 구조를 사용할 수 있습니다. 아래에 재귀적으로 무한으로 list를 생성하는 addOne 함수가 있습니다.

def addOne(n):
[n] + addOne(n + 1)

list = addOne(1) // [1, 2, 3, 4, 5, 6, …]

일반적인 compiler는 해당 함수를 호출하면 메모리 부족으로 문제가 발생하지만 lazy evaluation의 경우 재귀의 모든 depth를 계산하는게 아니라, 현재 실행되는 depth만 평가하기 때문에 문제가 발생하지 않습니다.

무한 자료구조를 선언할 수 있어도 쓸수가 없는데 왜 이게 이점인지 궁금하지 않나요? 비록 무한 자료구조 전체를 쓰지 않아도 일부는 사용할 수 있습니다.

oneToThree = list.takeFirst (3) 
print (oneToThree) // [1, 2, 3]
print (range (5, 10)) // [5, 6, 7, 8, 9]

위 처럼 인자로 몇 번째 데이터 or 범위 데이터를 전달하여 무한의 목록 중 일부를 사용할 수 있습니다. 이를 이용하여 ranges, sequences, cycles, 연속 사전 키 등의 유용한 개념을 정의할 수 있습니다.

--

--