Search

'curry'에 해당되는 글 2건

  1. 2008/10/31 JavaScript #3 함수-5
  2. 2008/10/26 JavaScript #3 함수-4

JavaScript #3 함수-5

IT/JavaScript 2008/10/31 00:35 Posted by Gony Taegony
14. Currying (커링)
  - 함수와 인수를 결합하여 새로운 함수를 만들 수 있게 한다.
  - 하나의 파라미터를 가진 함수를 여러번 호출하는 것과 같은 방법으로
    여러 개의 파라미터를 가진 함수로 변형하는 것을 말한다.
  - 자바스크립트는 자체적으로 currying 메소드가 없으므로 아래와 같이 구현한다.
  - 개인적으로 어디다 이런 기능을 써야할지는 아직 잘 모르겠다.
[code javascript]
var print = function (strLog) {
    document.write (strLog);
    document.write ('<br>');
};

// 함수 객체에 method 추가
Function.prototype.method = function (name, func) {
    if (!this.prototype[name]) {
        this.prototype[name] = func;
    }
};

Function.method ('curry', function () {
     // Array 객체의 slice 메소드를 가져온다.
    var slice = Array.prototype.slice;
     // Array 함수 객체에서 가져온 slice를 실행하는데
     // apply를 사용하여 this객체를 arguments로 바꿔준다.
     // 추후 Array의 concat을 사용하기 위함이다.
     // 왜냐하면 arguments는 length 메소드만을 지원하는 배열이다.
     // 따라서 엄밀히 말하면 배열 객체가 아니다.
     // 아래구문은 arguments를 배열객체로 만들어 args에 할당한다.
    var args = slice.apply (arguments);
     // that 은 curry 메소드를 사용하는 함수 객체를 가리킨다.
    var that = this;
     // curry 함수를 호출한 함수 객체를 변경한다.
     // 변경된 함수 객체를 호출하면 arguments와
     // 처음 curry 메소드 호출시 받은 arguments를
     // 합치게 된다.
    return function () {
        return that.apply (null, args.concat (slice.apply (arguments)));
    };
});

// 단순히 arguments를 모두 더해서 리턴하는 함수객체이다.
var add = function () {
    var iIndex = 0;
    var iCount = arguments.length;
    var iSum = 0;

    for (iIndex = 0; iIndex < iCount; iIndex ++) {
        iSum += arguments[iIndex];
    }
    return iSum;
};

// curry 를 호출해서 add1에 할당된 함수 객체는
// 1 이라는 arguments를 다음에 호출할 때 사용한다.
var add1 = add.curry (1);
// 변경된 add1을 호출한 함수 객체는 1 과 6을
// arguments 로 가지게 되므로 7을 리턴하게 된다.
print (add1 (6)); // 7
[/code]

12. Memoization (메모이제이션)
  - 함수가 이전에 연산한 결과를 저장하고 있는 객체를 사용하는 기법을 말한다.
  - 아래 두 함수를 비교해보면 이 기능을 어디에 쓸지 알 것 같다.
[code javascript]
// 피보나치 수열 함수이다.
// 아래의 연산을 하기 위해서는 453번의 호출이 발생한다.
var fibonacci = function (n) {
    return n < 2 ? n : fibonacci (n - 1) + fibonacci (n - 2);
};

for (var iIndex = 0; iIndex <= 10; i += 1) {
    print ('// ' + i + ': ' + fibonacci (i));
}

// 0: 0
// 1: 1
// 2: 1
// 3: 2
// 4: 3
// 5: 5
// 6: 8
// 7: 13
// 8: 21
// 9: 34
// 10: 55

// 위의 함수를 아래와 같이 변경하면 29번의 호출만 발생한다.
// 그 중 18번은 메모이제이션 결과를 얻기위한 과정이다.
var fibonacci = function () {
    var memo = [0, 1];
    var fib = function (n) {
        var result = memo[n];
        if (typeof result !== 'number') {
            result = flb (n - 1) + flb (n - 2);
            memo[n] = result;
        }
        return result;
    };
    return fib;
} ();
[/code]

    - 아래와 같이 일반화 시킬 수 있다.
[code javascript]
// 결과를 저장할 배열과 메모제이션을 할 함수를 인자로 받는다.
var memoizer = function (memo, fundamental) {
    var shell = function (n) {
        var result = memo [n];
        // 메모에 새로 저장할 데이터이면 fundamental을 호출한다.
        if (typeof result !== 'number') {
            result = fundamental (shell, n);
            memo[n] = result;
        }
        return result;
    };
    return shell;
};

// 피보나치 함수
var fibonacci = memoizer ([0, 1], function (func, n) {
    return func (n -1) + func (n - 2);
});

// 팩토리얼 함수
var factorial = memoizer ([1, 1], function (func, n) {
    return n * func (n - 1);
});
[/code]

공부한 책 : 자바스크립트 핵심가이드 - 더글라스 크락포드

JavaScript #3 함수-4

IT/JavaScript 2008/10/26 02:58 Posted by Gony Taegony
11. 콜백
  - 비연속적인 이벤트를 다루는데 좀더 효율적인 방법이다.
  - 예를들어 서버로부터 응답을 기다리지 않고 바로 리턴을 한 후 응답이 왔을 때
     해당 함수를 호출하는 것이 더 효율적이다.
[code javascript]
// 이 예제는 개념적인 설명이므로 함수 이름에 신경쓸 필요가 없다.

// send_request_synchronously 함수를 호출하면
//  리턴값이 올 때까지 대기해야한다.
request = prepare_the_request ();
response = send_request_synchronously (request);
display (response);

// send_request_asynchronously 함수는 호출즉시 바로 리턴되며
// 리턴값이 오면 함께 넘긴 함수를 직접 호출해준다.
request = prepare_the_request ();
send_request_asynchronously (request, function (response) {
        display (response);
    });
[/code]

12. 모듈
  - 모듈은 내부의 상태나 구현 내용을 숨기고 인터페이스만 제공하는 함수나 객체이다.
  - 함수와 클로저를 사용하면 모듈을 만들 수 있다.
  - 예제1 : String 객체에 deentityify 메소드를 추가한다.
               이 메소드는 문자열에서  HTML 엔터티를 찾고 상응하는 문자열로 대체한다.
[code javascript]
var print = function (strLog) {
    document.write (strLog);
    document.write ('<br>');
};
// 엔터티의 이름과 상응하는 문자들이 담긴 객체가 필요하다.
// 이 객체를 위치할 수 있는 부분은
// 1. 전역변수 - 가능한 사용을 하지 말아야 한다.
// 2. 함수 내에 정의 - 호출시 마다 객체화를 시켜야하기 때문에 실행시간 비용이 부담된다.
// 3. 클로저에 두고 이 객체를 access 할 수 있는 메소드를 따로 둔다.

// 함수 객체에 method 추가
Function.prototype.method = function (name, func) {
    if (!this.prototype[name]) {
        this.prototype[name] = func;
    }
};

String.method ('convertHTML', function () {
    var entity = {
        quot: '"',
        lt: '<',
        gt: '>'
    }

    return function () {
        return this.replace (/&([^&;]+);/g, function (a, b) {
                var r = entity[b];
                return typeof r ==== 'string' ? r : a;
            }
        );
    } ()); // 호출한 결과 리턴

print ('&lt;&quot;&gt;'.convertHTML ()); // <">
// string.replace (/&([^&;]+);/g, function (a, b) { 에서
// a 는 검색한 문자열, b 는 정규식으로 찾은 문자열을 말한다.
[/code]
  - 모듈 패턴은 안전한 객체를 생성하는데도 사용된다.
[code javascript]
var serial_maker = function () {
    var prefix = '';
    var seq = 0;
    return {
        set_prefix : function (p) {
            prefix = String (p);
        },
        set_seq : function (s) {
            seq = s;
        },
        gensym : function () {
            var result = prefix + seq;
            seq += 1;
            return result;
        }
    };
};

var seqer = serial_maker ();
seqer.set_prefix ('Q');
seqer.set_seq (1000);
var unique = seqer.gensym (); // Q1000
// set_prefix 나 set_seq 를 거치지 않으면 직접
// var prefix, var seq 를 접근할 수 있는 방법이 없다.
// 앞에서 배운 this, that 방법을 사용한 것도 아니기 때문에 불가능하다.
// serial_maker 가 정의한 메소드만 가능하다.

// 아래는 확장해서 접근하려는 예
seqer.get_prefix = function () {
   return prefix;
};
try
{
    print (seqer.get_prefix ());
}
catch (e) {
    print (e.name + ': ' + e.description);
} // ReferenceError: undefined
[/code]

13. 연속 호출 (Cascade)
  - 만일 모든 메소드가 this를 반환한다면 연속적인 호출이 가능하다.
[code javascript]
var cascade = {
    method1: function () {
        print ('1');
        return this;
    },
    method2: function() {
        print ('2');
        return this;
   }
};
cascade.method1 ().method2 ();
/* 결과
1
2
*/
[/code]

공부한 책 : 자바스크립트 핵심가이드 - 더글라스 크락포드