[Computation] 02 Lazy Evaluation, Lexical Scoping
Published:
In this post, 02 Computation lecture is introuduced.
1.1.6 함수 적용의 치환모형
1.1.6.2 Lazy Evaluation
정상 순서 평가의 변형.
R 해석기는 정상 순서를 사용하되, 전달인자가 두 번 평가되지 않도록 (memoization) 하는 지연 평가 (lazy evaluation) 메커니즘을 사용한다. 즉, 전달인자의 값이 필요한 시점에서 평가한다.
try_me <- function(a, b) {
if (a==0) {
1
} else {
b
}
}
try_me(0, stop("stop here"))
위 코드의 경우, 적용 순서 평가였다면 함수 호출시 인자 부터 평가하므로, stop("stop here") 가 함수 본체에 들어가기 전에 실행되어, 프로그램이 에러로 중단되었을 것이다.
반면, 정상 순서 평가의 경우try_me(0, stop("stop here")) 호출 시,a = 0, b = stop("stop here") 가 전달되는데, 지연 평가 덕분에 b는 즉시 계산되지 않고, “필요할 때만 계산하겠다”는 일종의 thunk(계산 지연 객체) 로 들어간다. a == 0 → 참(TRUE). 따라서 1을 반환하고, b는 전혀 평가되지 않음. 위 코드가 동작하는 이유는 정상 순서 평가 이기 때문. 즉, 정상 순서 평가와 지연 순서 평가의 차이를 보여주는 예는 아님.
1.1.7 내부 정의와 블럭 구조
1.1.7.1 Lexical Scoping, 자유 변수, 블럭 구조
블럭 구조란 다음과 같이, 함수 내부에 지역적으로 함수를 정의하는 구조를 의미한다.
Sqrt <- function(x) { is_good_enough <- function(guess, x) { Abs(square(guess) - x) < 0.001 } improve <- function(guess, x) { average(guess, x / guess) } sqrt_iter <- function(guess, x) { if (is_good_enough(guess, x) ) { guess } else { sqrt_iter(improve(guess, x), x) } } sqrt_iter(1, x) } Sqrt(2)형식 매개변수로 선언된 묶인 이름들의 범위는 함수 전체
sqrt_iter는 실행될 때마다 새로운 실행 환경 (call enviornment이 생긴다. (guess,x값 저장)하지만
sqrt_iter안에서is_good_enough나improve를 참조할 때는,- 자신이 정의된 환경(Sqrt Env)에서 찾는다.
이 환경은
Sqrt(2)를 호출할 때 한 번 만들어진 것이고, 재귀 중에 바뀌지 않는다.is_good_enough와improve함수 객체 자체는 하나씩만 생성됨.그 함수들이 바라보는 정의 환경(Sqrt Env)도 동일.
- 다만
sqrt_iter가 호출될 때마다 실행 환경이 새로 생길 뿐.
자유 변수 란, 어떤 함수(혹은 식) 안에서 정의되지 않았지만 사용되는 변수를 말한다.
현재 함수 내부에서 정의 X
현재 함수의 파라미터 X
외부 스코프에 의존하는 이름
위 3조건을 모두 만족시켜야 자유 이름
f <- function(y) { y + x }여기서
y는 매개변수 → 자유변수가 아님. (매개변수부터 시작하여 block까지 하나의 scope로 생각하면 될듯.)x는 함수 안에서 정의되지 않았음 → 자유 변수.이 함수가 실행되려면, 바깥쪽 환경(environment) 에서
x를 찾아야 함.Lexical Scoping 이란, 자유 변수의 값을 찾을 때, 함수가 정의된 위치(lexical context) 를 기준으로 스코프를 결정하는 방식을 말한다. R, Python, Scheme, 대부분의 함수형 언어가 이 규칙을 쓴다.
x <- 10 f <- function(y) { y + x } g <- function() { x <- 100 f(5) # 동적 스코핑이라면 여기서 105가 됨 } g() # 15함수
f안의x는 호출 시점이 아니라 정의 시점의 환경에서 찾아짐.Sqrt <- function(x) { is_good_enough <- function(guess) { abs(guess^2 - x) < 0.001 } ... }is_good_enough내부에서 쓰인x는 자유변수.하지만 함수
Sqrt가 정의될 때 바깥에서 매개변수x를 받아둠.따라서 내부 함수는 자기 정의 시점의
x를 참조 → 렉시컬 스코핑 덕분에 잘 동작.함수가 실행될 때, 내부에서 이름(변수) 를 찾는다.
먼저 자기 함수의 지역 스코프(local scope) 에서 찾는다.
없으면, 함수가 정의된 위치의 바깥 환경(lexical parent scope) 으로 올라간다.
최상위까지 올라가면서 찾는다. (없으면 오류)

Leave a Comment