자바스크립트 튜플 만들기

자바스크립트에는 튜플이 없어요. 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"
Advertisements

3 thoughts on “자바스크립트 튜플 만들기

  1. 흥미롭네요. 다만 id의 구현을 실행해보면 1이 안나옵니다. 아래와 같이 되야하지 않나요?

    function id(x) {
    return x(function (a) { return a; });
    }

    Liked by 1명

  2. 잘 읽었습니다. ^^ 요즘식으로 하면

    const makePair = (a, b) => f => f(a, b);
    const fst = p => p((a, b) => a);
    const snd = p => p((a, b) => b);

    const p = makePair(‘foo’, ‘bar’);
    console.log(fst(p)); // ‘foo’
    console.log(snd(p)); // ‘bar’

    이렇게 쓸 수 있겠네요.

    http://babeljs.io/repl/#?evaluate=true&presets=es2015&code=const%20makePair%20%3D%20(a%2C%20b)%20%3D%3E%20f%20%3D%3E%20f(a%2C%20b)%3Bconst%20fst%20%3D%20p%20%3D%3E%20p((a%2C%20b)%20%3D%3E%20a)%3Bconst%20snd%20%3D%20p%20%3D%3E%20p((a%2C%20b)%20%3D%3E%20b)%3Bconst%20p%20%3D%20makePair('foo'%2C%20'bar‘)%3Bconsole.log(fst(p))%3B%20%2F%2F%20’foo’console.log(snd(p))%3B%20%2F%2F%20’bar’

    좋아하기

댓글이 닫혀있습니다.