치환 모델을 이용한 참조 투명성 검사

Keunjae Song·2020년 3월 13일
0

fp

목록 보기
4/6

스칼라로 배우는 함수형 프로그래밍을 읽고 정리한 글입니다.

저자는 치환 모델을 "프로그램 평가에 대한 간단하고도 자연스러운 추론 모형"이라고 얘기한다.
나는 그냥 표현식들에 대해 참조 투명성을 검사하기 위해, 표현식을 해당 표현식의 결과로 바꿨을 때의 코드의 형태라고 이해하고 있다.

한 가지, 참조에 투명한 예제를 살펴보자.

scala > val x = "Hello, World"
x: java.lang.String = Hello, World
scala > val r1 = x.reverse
r1: String = dlroW, olleH
scala > val r2 = x.reverse
r2: String = dlroW, olleH

이제 이 x항의 모든 usage를 x의 표현식(정의)로 치환하면 아래와 같다.(이 치환 과정 및 치환된 코드를 치환 모델이라고 생각한다.)

scala > val r1 = "Hello, World".reverse
r1: String = dlroW, olleH
scala > val r2 = "Hello, World".reverse
r2: String = dlroW, olleH

치환 모델의 결과를 보면, r1과 r2의 결과가 치환 전과 그대로 같다.
따라서 x는 참조에 투명하다라고 얘기할 수 있으며, r1과 r2도 똑같이 참조에 투명하므로 나중에 다른 부분에서의 r1과 r2의 usage를 치환하여도 다른 결과가 생기지 않는다.

그렇다면 참조에 투명하지 않은 StringBuilder의 append 예제를 보자.

scala> val x = new StringBuilder("Hello")
x: java.lang.StringBuilder = Hello

scala> val y = x.append(", World")
y: java.lang.StringBuilder = Helo, World

scala> val r1 = y.toString
r1: java.lang.String = Hello, World

scala> val r2 = y.toString
r2: java.lang.String = Hello, World

여기서도 아직 r1과 r2는 같다.
그러면 이제 y를 치환해보면 어떻게 될까?

scala> val x = new StringBuilder("Hello")
x: java.lang.StringBuilder = Hello

scala> val r1 = x.append(", World").toString
r1: java.lang.String = Hello, World

scala > val r2 = x.append(", World").toString
r2: java.lang.String = Hello, World, World

r1과 r2의 결과가 같지 않다.

append는 결국에 StringBuilder의 이전 상태(문자열)가 유지되는 게 아닌 바꿔버리는 함수이다.
r1은 x가 "Hello"라는 값이 아닌 "Hello, World"를 참조하게 만들었고,
r2는 x가 참조하고 있던 "Hello, World"가 아닌 "Hello, World, World"를 참조하게 했고 그 값을 사용하게 된 것이다.

즉, x.append()를 호출할 때마다 x가 참조하고 있던 객체가 달라지는 것이다.

결국 y는 참조에 투명하지 않으며 append는 비순수 함수이다라는 결론에 도달하게 된다.

0개의 댓글