자바스크립트에는 튜플이 없어요. 1과 “abc” 두 개의 값을 변수에 저장하거나 리턴하려면 오브젝트 리터럴을 만들거나 배열에 저장해야 하는 불편함이 있지요.
> {n: 1, s: "abc"} { n: 1, s: 'abc' } > [1, "abc"] [ 1, 'abc' ]
오브젝트 리터널은 각 필드마다 이름을 지어줘야 하고, 배열은 길이가 고정되어 있지 않죠. 매번 여러 개의 값을 변수에 저장하거나 리턴할 때마다 불편함을 감수하며 살던 자바스크립트 개발자는 어느날 곰곰이 생각을 해요.
“튜플이란 게 별 것 아닌데… 그냥 (1, “abc”) 이런 걸 표현할 수 있으면 되는 거잖아. 원소 a, b를 들고 있는 데이터 타입이니 (a, b)”
하지만 자바스크립트는 어쨌거나 튜플 타입이 없기 때문에 “(a, b)”라는 타입을 어떻게 만들어낼 수 있을까 고민에 고민을 거듭했어요.
그러다가 문득 비동기 프로그래밍에 사용하는 callback (continuation) 개념을 떠올렸어요. a라는 값은 사실 a를 인자로 r을 리턴하는 함수 (a -> r)을 인자로 받아 다시 r을 리턴하는 고차 함수로 표현할 수 있다는 개념이죠.
a ~is isomorphic to~ (a -> r) -> r
예를 들어 var a = 1을 다음과 같이 표현할 수 있죠.
function makeA(a) { return function cont(f) { return f(a); }; } function id(x) { return x; } var a = makeA(1);
a(id)
를 호출하면 1
이 나오니깐 두 코드는 완전히 똑같아요.
같은 방법으로 (a, b)도 ((a, b) -> r) -> r 함수로 표현하면 되겠다고 생각했어요. 자바스크립트에 (a, b)라는 타입은 없지만, 자바스크립트 함수는 인자를 여러 개 받을 수 있으니깐 (a, b) -> r이라는 타입은 가능하다는 것에 착안을 한거죠. 이런 타입을 갖는 함수는 사실상 하나 밖에 없으니깐 구현은 간단했어요.
function makePair (a, b) { return function (f) { return f(a, b); }; }
이제 makePair(1, “abc”)라고 하면 (1, “abc”) 튜플이 만들어지게 되었어요. 이렇게 만든 튜플을 사용하려면 첫 번째 원소와 두 번째 원소를 끄집어 낼 수 있는 함수 fst와 snd 함수가 필요하겠죠?
튜플 p 자체가 (a, b) -> r 타입의 함수를 인자로 받아 r을 리턴하는 함수니깐, fst와 snd의 함수 구현도 정해져 있는 것이나 마찬가지에요. fst가 p에 넘기는 함수의 타입은 (a, b) -> a가 되고 a와 b 중에서 a를 리턴하면 되죠. snd가 p에 넘기는 함수의 타입은 (a, b) -> b이니깐 a와 b 중에서 b를 리턴하면 되고요.
function fst (p) { return p(function (a, b) { return a; }); } function snd(p) { return p(function (a, b) { return b; }); }
자 이제 자바스크립트도 튜플 생성자와 첫 번째, 두 번째 인자를 끄집어낼 수 있는 함수를 가지게 되었어요.
> var p = makePair(1, "abc"); > fst(p); 1 > snd(p); "abc"
Pingback: 자바스크립트 튜플 만들기 | 서광열의 코딩 스쿨