이 시리즈는 "스칼라로 배우는 함수형 프로그래밍"을 TypeScript로 실습하는 과정을 정리하고 있습니다.
JavaScript의 Math.rand는 호출할때 마다 매번 다른 값을 리턴한다. 이 함수를 호출할때마다 갱신되는 어떤 전역 상태가 존재한다고 가정할 수 있을것이다. 이와 비슷하게 클래스들은 내부에 상태를 지니고 특정 매서드가 호출될때마다 이전 상태를 파괴하고 새로운 상태로 갱신하는 경우가 많다.
상태 갱신은 부수 효과로서 수행되므로 참조에 투명하지 않다. 그렇기 때문에 검사, 합성, 모듈화가 어렵고 쉽게 병렬화 할 수도 없다.
1~6까지의 숫자를 얻기를 기대하는 랜덤함수가 실제로는 0~5까지의 숫자를 리턴하고 있더라도 약 83%의 확률로 테스트 코드가 통과할 것이다. 명세대로 작동하지 않더라도 실패 상황을 신뢰성있게 재현할 수 있다면 이상적이다.
프로그램과 버그가 더 복잡하고 미묘할 때에는 버그를 신뢰성 있게 재현할 수 있는 프로그래머의 능력이 훨씬 중요하다.
실패 상황을 재현하기 위해서는 상태가 있는 클래스의 경우 seed값과 호출 횟수등을 일치시켜 내부 상태를 완전히 동일한 상태로 만들어야 한다. 위에서 말한바와 같이 이전 상태가 파괴되기 때문에 이를 보장하기는 아주 어렵다. 해법은 애초에 부수 효과를 피하는 것이다.
상태 갱신을 명시적으로 드러내면 참조 투명성을 되찾을 수 있다. 이전과 다르게 랜덤값을 돌려주고 상태를 제자리(in-place)에서 변경하는 대신 랜덤값과 새로운 상태를 돌려주고 내부 상태는 변경시키지 않는다.
이 두가지 관심사를 분리한다. 새 상태로 무엇을 할지는 호출자의 마음이다. 상태 변경의 구현 자체는 여전히 함수안에 존재하고 호출자는 모른다는 점에서 상태는 여전히 캡슐화 되어있다.
상태 있는 API를 순수하게 만드는것은 난수 발생에 국한되지 않고 자주 등장하며, 항상 동일한 방법으로 해결가능하다.
다음 상태로의 전이를 명시적으로 드러내는 과정은 계산된 다음 상태를 프로그램의 나머지 부분에 전달하는 책임을 호출자에게 지우는것이다.
https://github.com/JsonKim/fpinscala-with-typescript/commit/1c3538e16bb6a09e78d8073ff0baf40443f95499
함수적 프로그램을 작성하다 어색하거나 지겨운 상황에 처했다면 아직 뭔가를 덜 추상화 했기 때문일것이다. 순수 함수를 이용한 프로그래밍은 설계 공간을 크게 단순화한다.