JS 제너레이터와 함수형 프로그래밍

Jooyung Han (한주영)
4 min readJan 16, 2018

--

JavaScript 제너레이터 이야기를 꽤 한 것 같다. 이번에는 함수형 프로그래밍 관점에서 이야기를 해볼까 한다. (주의: 이 글은 그냥 개인적인 견해라는 점을 분명히 한다.)

JavaScript 제너레이터는 함수형 프로그래밍의 모나드와 매우 닮아 있다. 아마도 이것 때문에 그렇게 제너레이터 이야기를 많이 하게 된 것 같다.

함수형 프로그래밍, 특히 하스켈과 같은 순수 함수형 프로그래밍에서 모나드는 매우 중요한 역할을 한다. a -> b 라는 단순한 값 계산이 아니라 a -> X b 처럼 어떤 효과 X를 동반하는 계산을 나타내는 방법이기 때문이다. X 라는 효과를 “모나드”로 만드는 순간 함수형 프로그래밍이 그렇게 추구하는 “합성에 의한 프로그래밍”이 다시 가능해지는 것이다.

예를 들어, a -> b 함수 fb -> c 함수 g 는 딱 봐도 너무나 쉽게 합성할 수 있다. af를 지나 b가 되고, 거기에 g 를 붙이면 b가 다시 c가 된다.

그런데 a -> X b 함수 fb -> X c 함수 g는 합성하기가 곤란하다. b가 계산 결과에 나타나기는 하지만 부수효과(side effect)를 감추지 못하는 순수 함수형 언어는 X 라는 타입생성자로 그 효과를 드러내야만 한다. 그러다 보니 X b 결과에 g 를 바로 가져다 붙일 수고 없다. 바로 여기 모나드가 등장하는 것이다.

X에 모나드 패턴을 적용시키면, 즉 X에 대해 >>= , bind, flatMap, .. 뭐가 되었건, 이 연산자를 정의하기만 하면 a -> X b 함수와 b -> X c 함수를 합성하여 a -> X c 가 만들어지게끔 한 것이다.

하스켈은 IO를 처리할 방법을 찾다가 이 모나드 패턴을 발견했고, IO를 모나드로 만들면서 정말 “깔끔하게” IO를 처리할 수 있게 되었다. 나아가 거의 모든 부수효과들을 모나드로 만들어버렸다.

모나드는 부수 효과를 수반하는 계산을 효과적으로 합성하기 위한 도구라고 했다. 그런데 긴 모나드 여정 뒤에, 모나드에서 “부수 효과”마저 배제하고, 오로지 “합성”에만 포커스를 둔 새로운 모나드가 발견(발명?)되었다. 바로 Free Monad다.

Free 모나드는 “효과”마저 인자로 추출하였고, 결과적으로 남은 구조는 오로지 모나드 합성만을 위한 형태가 되었다. Free 모나드로 만들어지는 어떤 값(계산식, 혹은 프로그램)은 사실 아무런 효과를 수반하지 않으며, 주입된 “효과”라는 것은 나중에 해석하기 위한 힌트 정보만 담당한다. 이제 이 Free 모나드로 만들어진 값이 실제로 어떤 효과를 발휘하려면 “해석기”가 필요해진다.

Free 모나드를 설명하는 글에는 이런 내용들이 나온다.

  • Free 모나드는 AST 를 만들어내고, 나중에 해석기가 이 AST를 처리한다.
  • Free 모나드로 만들어진 프로그램은 코루틴처럼 동작한다. 다른 한쪽이 해석기가 된다.

다시 말하지만, Free 모나드는 “효과”마저 배제한 순수한 계산 식을 만들 수 있게 했고, 나중에 해석기에서 “효과”를 처리한다. 그리고 Free 모나드 프로그램은 해석기와 코루틴 처럼 동작한다.

한참 돌고 돌아 다시 JavaScript 제너레이터를 이야기 할 수 있게 되었다. Free 모나드의 마지막 설명을 보면 이것이 딱 제너레이터를 설명하는 것 같다.

이미 순수와는 담쌓은 JavaScript지만 “효과”를 프로그램에서 분리 시키는 것은 개발자에게 굉장히 강력한 도구가 된다. 여러가지 효과가 코드에 섞여버린다든지 혹은 런타임이 처리하는 효과가 어떤 형식을 강요한다든지 하는 경우에 이런 효과들을 프로그램에서 분리시키고 해석기에서 처리할 수 있기 때문이다.

JavaScript 제너레이터는 순수 함수형 프로그래밍에서 Free 모나드로 작성한 프로그램 역할을 할 수 있다. 해석기에게 부탁할 내용이 있다면 yield 로 요청을 전달하면 되고, 해석기는 그 요청을 처리한 다음 다시 제너레이터에 넘겨준다. (이 구조를 가장 잘 활용하고 있는 라이브러리가 아마도 Redux-saga가 아닐까 한다.)

interpret(function *() {
var response = yield request;
...
})

--

--

Jooyung Han (한주영)

가끔 함수형 프로그래밍 관련 글을 쓰거나 번역합니다. “개미 수열을 푸는 10가지 방법"이란 책을 썼습니다. https://leanpub.com/programming-look-and-say