본문 바로가기

Web/JavaScript

함수형 자바스크립트 7. 수집하기, 거르기, 찾아내기, 접기

기초내용

컬렉션 중심 프로그래밍에서는 배열이나 돌림직한 데이터를 다룬다.

함수형 프로그래밍에서 사용하는 기법으로 함수들의 응용과 조합을 기반으로 한다고 한다.

컬렉션은 데이터를 모아논 구조체이다.

컬렉션을 중심으로 수집하고 찾아내고 거르고 축약하면서 어떠한 결과를 만들어내는 프로그래밍 방식인 듯 하다.


수집하기, 거르기, 찾아내기, 접기의 각각 대표함수가 존재한다.

대표함수는 추상화 레벨이 가장 높아서 각각의 특화함수를 만들 수 있는 함수이다.

예를들어 map을 이용해 values와 pluck라는 특화함수를 만들 수 있다.

수집하기

_map에서 공부한 것처럼, 말 그대로 주어진 데이터에서 내부에 있는 값을 수집하는 기능이다.

_values: (키, 벨류) 형식의 컬렉션에서 벨류의 값들을 수집한다.

_pluck: 배열 내부 객체에서 지정한 키에 해당하는 값들을 수집한다.


이외에도 _identity라는 함수가 있다.

이 함수의 용도는 인자로 들어온 값을 그대로 반환한다.

자바 Stream API를 공부할 때도 보았던 이름인데, 그 당시에는 이걸 왜 쓰는지 전혀 몰랐다.

identity([1, 2, 3])을 사용하면 그저 [1, 2, 3] 을 반환할 뿐이니....



데이터 구조, 변수, 파라미터 혹은 반환값으로 사용 가능한 일급 함수라는 개념이 있고,

다시 그 일급 함수 중 함수를 받아서 함수를 반환하는 것을 고차 함수라고 한다.

다른 함수를 이용해서 완전히 새로운 함수를 조립할 수 있다고 한다.


identity의 용도는 보조함수로서 존재한다.

즉, 코드를 작성할 때, 어떠한 고차함수를 선택하여 수집할 것인가 등을 결정하고, 수집하는 방법을 보조함수로 작성한다.


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

/* values - (k, v)에서 v의 값들을 수집 */

function _values( data ) {

   return _map( data, function(val) {

       return val;

   });

}

console.log( _values(users[0]) );

function _values( data ) {

   return _map( data, _identity );

}

console.log( _values(users[0]) );

var _values = _map( _identity );

console.log( _values(users[0]) );    

cs

function(val) { return val; } 이 부분이 identity의 구현이다.

9, 14번째 줄을 살펴보면 identity를 보조함수로 사용하면서, _values의 구현이 명료해졌다.

자바와 같은 객체지향에서는 데이터의 형태를 결정하고, 클래스를 만들고, 데이터를 조작할 메소드를 작성하면서 데이터에 초점을 두면서 개발해왔다.

지금까지 공부한 함수형 패러다임에서는 함수를 만들고, 해당 함수에 맞는 데이터를 구성하면서 개발해 나가야 한다. 이러한 사고방식이 습관화된다면, 자바에서 하던 것처럼, 데이터의 복잡한 상속관계, 이를 처리하기 위한 다형성, 다형성을 위한 타입체크 등에 들어가는 노력이 많이 줄어들 것 같다.


거르기

_filter와 같이 데이터를 검사하여 일부 데이터를 추출하거나 거르는 기능이다.

_reject: true로 평가된 값들을 제외시킨다( filter의 반대 )

_compact: true로 평가되는 값만 남긴다(0, null, undefined 등은 제외된다)


거르기도 negate라는 보조함수가 존재한다.

어떤 함수의 실행결과를 반대로 돌리는 함수이다.


1

2

3

4

5

6

7

8

9

function _negate( func ) {

   return function(val) {

       return !func(val);

   };

}

var _reject = _curryr(function( data, predi ) {

   return _filter(data, _negate(predi));

});

Colored by Color Scripter

cs


위처럼, _filter에서 조건검사르 하는 predicate 함수의 실행결과를 반대로 전환하여

_reject를 구현할 수 있다.

identity와 마찬가지로 negate 또한 자바 Stream API에 존재한다.


찾아내기

데이터를 순회하며 특정 조건을 검사하여 무언가를 찾아내는 기능이다.

_find: 배열에서 조건에 해당하는 값을 처음 만났을 때 해당하는 값을 반환한다.

_find_index: _find와 같지만, 값이 아닌 index를 반환한다.

_some: 배열에서 조건을 만족하는 값이 하나라도 있으면 true, 그렇지 않으면 false를 반환한다.

_every: 배열에서 모든 값이 조건을 만족하면 true, 하나라도 만족하지 않는다면 false를 반환한다.



1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

console.log(_every([1, 2, 5, 10, 20], function(val) {

   return val > 10;

}));

console.log(_every([12, 24, 50], function(val) {

   return val > 10;

}));

console.log(

   _some([1, 2, 0, 10])

);

console.log(

   _some([null, false, 0])

);

console.log(

   _every([1, 2, 3, 10])

);

console.log(

   _every([null, 2, 1])

);

console.log(

   _some(users, function(user) {

       return user.age < 20;

   })

);

Colored by Color Scripter

cs


위의 예제는 모두 그러하느냐, 혹은 하나라도 그러하느냐를 고차함수(_some, _every)로 선택하고,

그러느냐가 무엇인가를 보조함수로 조합해나아가는 예제이다.

찾아내기 부분에서는 특별한 궁금증이 생기진 않았다.


접기(축약)

앞서 공부한 _reduce가 대표함수이다.

배열과 같은 목록을 받아 값을 축약하거나, 분리 혹은 집계와 같은 접기를 한다

min: 최대값

max:: 최소값

min_by, max_by: 어떤 조건을 통해서 비교할 것인지를 iterator 보조함수로 평가한다.


reduce와 같은 고차 함수를 사용할 때 주의할 점이 있다.

보통 순차적인 for를 대체하는 함수 정도로 사용하는데, for문은 데이터를 순차적으로 순회한다.

하지만 reduce는 순수함수로서 평가순서와 상관없이 어떤 해당하는 결과를 만들어낸다는 사고를 가져야한다.

0, 1, 2, 3..... 100 이 아닌 1, 100, 5와 같은 무작위 순서라고 고려하고 2가지 데이터를 비교한다는 생각을 가져야한다.


1

2

3

_reduce(data, function(a, b) {

       return a < b ? a : b;

   });

cs

와 같은 식으로 reduce를 사용한다면 a와 b는 순차적이 아닌 무작위 숫자라고 생각하라는 의미인것 같다.


접기에 해당하는 group_by, count_by는 다음 강의에서 진행한다.