함수형 프로그래밍 #1

Y·2020년 8월 9일
0

Functional JavaScript(Michael Fogus)을 바탕으로 작성되었습니다.

Chapter 1


Functional JavaScript 의 소개

The Case for JavaScript


자바스크립트는 굉장히 유연한(flexible)한 언어이다. 가령, 함수를 통해 함수를 리턴할 수 있으며 이를 함수형 프로그래밍이라고 부른다. 간단한 예시로 다음과 같은 코드가 있다.

function splat(fun) {
  return function(array) {
    return fun.apply(null,array);
  };
}

var addArrayElements = splat(function(x,y) {return x+y });

addArrayElements([1,2]);

splat이라는 함수는 어떠한 함수 fun을 인자로 받고, array를 인자로 받는 함수를 리턴하고, 그 함수는 apply메서드를 통해 해당 배열의 요소들을 fun함수에 인자로 넘긴다.
따라서, addArrayElements에서는 fun : function(x,y){return x+y}) 이고, 이 함수에 인자로 배열 [1,2]를 넘겨 1 +2가 실행되어 3의 리턴값을 가지게 된다.

또 다른 예시로, splat함수의 정반대의 기능을하는 unsplat함수도 구현할 수 있다.

function unsplat(fun) {
  return function () {
    return fun.call(null,_toArray(arguments));
  };
}

var joinElements = unsplat(function(array) { return array.join(' ') });
joinElements(1,2);

여기서는, arguments 유사배열객체를 배열로 만들어서 Array.prototype.join(' ')메서드를 통해 인자들을 묶어 하나의 문자열을 반환한다. 여기서 사용된 _toArray()메서드는 Array.from()과 같은 역할을 하는것 같다. applycall의 차이점은, apply는 단일배열을 호출함수에 넘기고, call은 인수목록을 넘긴다. 이처럼, applycall은 자바스크립트의 유연성을 주는 기능들이지만, 극히 일부의 기능들이다.

Getting Started With Functional Programming


Functional programming is the use of functions that transform values into units of abstraction, subsequently used to build software systems.

함수형 프로그래밍이란, 값이나 행위를 추상적인 단위로 변형시키고 이를 함수화 하는 과정을 통해 소프트웨어 시스템을 만드는 것이다. 맞게 해석한건지 모르겠다.. 딱히 와닿지 않는다.
공통적인 속성과 최소 단위 행위는 모두 따로 함수화하고, 이를 통해 더 복잡한 함수를 만든다고 생각하면 될 것 같다.

Functions as Units of Abstraction


다음의 예시를 보자.


function parseAge(age) {

    if (!_.isString(age)) throw new Error("Expecting a string");
    var a;

    console.log("Attempting to parse an age");

    a = parseInt(age, 10);

    if (_.isNaN(a)) {
      console.log(["could not parse age:",age].join(' '));
      a=0;
    }
  return a;
}

이 코드는 틀린코드가 아니며, 잘 돌아가는 코드이다 .하지만 이런 방식의 코드는 만약 에러메세지나, 경고메세지 등의 내용을 바꾸자고 할 때, 해당 코드 라인을 찾아야하고 비슷한 구조를 사용했다면 전부다 수정해줘야 한다. 이렇기 때문에, abstract개념을 사용하면 보다 편하다.

function fail(thing) {
  throw new Error(thing);
}

function warn(thing) {
  console.log(["Warning:",thing].join(' '));
}

function note(thing) {
  console.log(["NOTE:",thing].join(' '));
}

위에서 어떠한 역할을 하고자 하는 코드마다 함수를 만들어준다면, 그 역할을 바꿔주는데 있어서 아주 효율적인 방법으로 수행할 수 있다.

Encapsulation and Hiding


자바스크립트에서는 클로저를 사용하여 데이터를 숨길 수 있다. 가령, 다음과 같은 상황이다.

const buffAr = [
  "나는 ",
  "",
  ". 난",
  "",
  "에 살고, 나는 ",
  "",
  "살이다."
  ];

function getCompletedStr(name,city,age){
  buffAr[1] = name;
  buffAr[3] = city;
  buffAr[5] = age;
  
  return buffAr.join('');
}

const str = getCompletedStr('PSM', 'seoul', 25);
console.log(str)

위 코드에서는 buffAr 데이터가 전역코드로 노출되어있기 때문에, 쉽게 접근하여 데이터를 수정할 수 있다. 이를 캡슐화를 이용하면, 클로저를 통해 데이터를 숨길 수 있다.

const getCompletedStr = (function(){
  const buffAr = [
  "나는 ",
  "",
  ". 난",
  "",
  "에 살고, 나는 ",
  "",
  "살이다."
  ];
  
  return (function(name,city,age){
    
    	buffAr[1] = name;
  	buffAr[3] = city;
  	buffAr[5] = age;
  
  	return buffAr.join('');
  });
})();

const str = getCompletedStr('PSM', 'seoul', 25);
console.log(str);

지금은 배열을 예시로 들고있지만, 웹에서 생각해보면 buffAr이라는 정보가 클라이언트에 나타나는 데이터였다면, 위와 같은 방식으로 클라이언트에서 나타나지 않게 구현한 셈이다. 클로저 역시도 함수의 형태이다. 클로저를 활용한 여러 함수테크닉을 사용할 수 있다.

Functions as Units of Behavior


const array =[1,2,3];
array[1]; // 2

위 코드는 배열의 1번 인덱스의 요소를 읽는 코드이다. 만약 array 변수가 숫자를 담고있었다면 오류가 발생한다. 주어진 데이터의 n번째 요소를 인덱싱하는 함수를 구현해보자.

function nthIndex( data, index ) {
  if(!_.isNumber(index)) fail("Fail");
  if(!isIndexed(data)) fail("Fail");
  if((index <0) || (index > a.length -1))
    fail("Fail");
  
  return a[index];
}

function isIndexed(data) {
  return _.isArray(data) || _.isString(data);
}

function fail(thing) {
  throw new Error(thing);
}

이는 data가 문자열인지 배열인지 찾는 과정을 추상화하였고, index가 숫자인지, 범위를 초과하지않는지를 체크한다. 주어진 모든 데이터에 대해서 데이터타입을 확인해야하기 때문에, 이를 따로 함수로 관리하는 것이 핵심이다.

이처럼 어떠한 값이나 최소한의 행위를 함수로 만들고, 그 함수들로 다른 복잡한 함수를만들며, 그 함수들을 인자로 받아서 어떠한 행위를 수행하는 더 복잡한 함수들을 만드는 것을 함수형 프로그래밍이라고 한다.

profile
연세대학교 산업공학과 웹개발 JavaScript

0개의 댓글