ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Functional] 고차 함수
    programing/Language 2019. 12. 29. 15:50

    안녕하세요, Einere입니다.

    (ADblock을 꺼주시면 감사하겠습니다.)


    고차함수

    1. 함수를 인자로 받는다.
    2. 함수를 반환한다.

     

     

    함수를 인자로 받는 함수

    best

    function best(compare, collection) {
        return _.reduce(collection, function(x, y) {
            return compare(x, y) ? x : y;
        });
    }

    best함수는 어떤 배열에서 최적의 값을 반환하는 함수입니다.

    인자로는 최적의 값을 찾기 위한 compare함수와 대상 배열인 collection이 있습니다.

     

    iterateUntil

    function iterateUntil(func, check, init) {
        let ret = [];
        let result = func(init);
        
        while(check(result)) {
            ret.push(result);
            // pipeline
            result = func(result);
        }
        
        return ret;
    }

    iterateUntil은 특정 상태까지 주어진 동작을 반복한 결과를 반환하는 함수입니다.

    인자로는 반복할 동작인 func함수와 계속할지 판단하는 check함수, 초기값인 init이 있습니다.

    여기서 이전의 결과를 다음 함수의 인자로 넘겨주는 것을 파이프라이닝이라고 합니다.

     

    함수를 반환하는 함수

    always

    function always(capturedValue) {
        return function() {
            return capturedValue;
        }
    }

    always함수는 cpaturedValue를 closure로 가진 익명 함수를 반환하는 함수입니다.

    따라서 다른 함수의 인자로 상수를 전달하는 대신, 함수로 전달하기 위해 사용할 수 있는 함수입니다.

    해당 함수는 combinator라고 합니다. 함수형 프로그래밍에서는 중요하다고 하네요.

     

    omgenerator

    const omgenerator = (function(init) {
        let counter = init;
        
        return {
            uniqueStr(prefix) {
                return `${prefix}${counter++}`;
            }
        };
    })(0);
    
    const result1 = omgenerator.uniqueStr('foo');
    console.log(result1);
    // "foo0"
    
    const result2 = omgenerator.uniqueStr('bar');
    console.log(result2);
    // "bar1"

    omgenerator는 특정 키워드와 순번을 붙인 결과를 출력하는 함수입니다. 즉, 변수를 캡처하는 함수를 반환하는 함수입니다.

    그러나 위와 같은 패턴은 명확히 구별되는 모듈이나 네임스페이스를 만드는 상황이 아니라면, 사용하지 않는 것을 권장한다고 합니다. (해당 함수는 상태를 가지고 있기 때문에, 동일한 입력에 다른 출력을 하기 때문입니다.)

     

    fnull

    function fnull(func) {
        // 인자로 받은 함수인 func를 제외한 인자들의 기본값들을 받는다.
        // 굳이 arguments를 쓴 이유를 모르겠지만.. 아마 es5기준이라 그런듯?
        const defaults = _.rest(arguments);
        
        return function() {
        	// 해당 함수의 인자들을 검사하여, 기본값들로 대체한다.
        	const args = _.map(arguments, function(e, i) {
            	return existy(e) ? e : defaults[i];
            });
            
            // 정제과정을 거친 인자들을 적용시킨 결과를 반환한다.
            return func.apply(null, args);
        }
    }
    
    // 여기서 두번째 인자는 acc의 기본값, 세번째 인자는 val의 기본값이 된다.
    const safeMul = fnull(function(acc, val){
        return acc * val;
    }, 1, 1);
    
    
    const result = [1, 2, 3, null, 5].reduce(safeMul);
    // result : 30

    fnull과 같은 함수를 이용한다면, 인자값을 검사하기 위한 param[key] || someDefault같은 패턴이 필요없다.

     

    총 정리

    checker

    function checker(...validators) {
        return function(obj) {
            // 인자로 받은 검증자들로 obj를 검사한다
            // 만약 실패를 한다면, 에러 메세지를 배열에 추가한다.
            return validators.reduce(function(errors, checker) {
                if(!checker(obj)) errors.push(checker.message);
    
                return errors;
            }, []);
        }
    }
    
    const alwaysPass = checker(always(true), always(true));
    alwaysPass({});
    // []
    
    const fail = always(false);
    fail.message = "always fail";
    const alwaysFail = checker(fail);
    alwaysFail({});
    // ["always fail"]

    checker함수는 true나 false를 반환하는 찬반형 검증자 함수들을 인자로 받아 익명의 검증 함수를 반환합니다.

    익명의 검증 함수는 객체를 인자로 받은 후, 클로저로 들고있던 찬반형 검증자 함수들을 차례대로 적용합니다. 이 때 거짓을 반환하는 검증자가 있는 경우, 해당 검증자의 오류 메세지를 모읍니다. 익명의 검증 함수는 이렇게 모은 오류 메세지들을 반환합니다.

     

    makeValidator

    // func는 반드시 반환값이 boolean이어야 한다
    function makeValidator(func, message) {
        const f = function(...args) {
            return func.apply(func, args);
        };
        f.message = message;
        
        return f;
    }
    
    function isObject(input) {
    	return input instanceof Object;
    }
    
    const objChecker = checker(makeValidator(isObject, "maybe it's not Object"));
    
    objChecker({});
    // []
    
    objChecker(100);
    // ["maybe it's not Object"]

    검증자 함수를 정해진 규칙에 따라 만들기 위해, 위와 같은 함수를 만들 수도 있습니다.

     

     

    참고

    마이클 포거스, 『함수형 자바스크립트 : 새롭고 올바른 자바스크립트 프로그래밍 기법』, 한빛미디어(2014).

    댓글

Designed by black7375.