clojure (뿐만 아니라 함수형 언어나 문법) 를 공부하면서 자주 헷깔리는 게 map 이랑 reduce 인 것 같다.
다시 한 번 정리하는 시간을 갖기 위해 메모한다.
map은 mapping 한다고 생각하면 좋을 것 같다.
기본적으로 첫번째로 인자로 함수를 받고, 두번째 인자로 리스트 등을 인자로 받는다.
리스트의 원소 각각에 함수를 적용하여 매핑된 결과의 리스트를 반환한다.
수학 시간에 함수를 배울 때 자주 나오는 정의역, 치역을 보여주는 그림을 생각하면 될 것 같다.
함수 f가 y=x+1 이고, x는 {0,1,2,3} 일 때 y의 값은?
f(x) = y
f
x(정의역) -> y(치역)
0 -> 1
1 -> 2
2 -> 3
3 -> 4
y = {1,2,3,4} 이다.
이걸 clojure로 표현하면
=> (def x [0 1 2 3])
=> (map f x)
=> [1 2 3 4]
라 볼 수 있다.
추가로 clojure 에서는 리스트를 여러개 받을 수 있는데 이 때는 각각의 리스트의 원소 순서대로 매핑을 한다.
=> (map + [1 2 3] [1 3 5] [1 1 1])
=> [3 6 9]
위의 결과들을 볼 때, map 함수의 특징 중 하나는 인자로 들어간 리스트의 원소의 개수와 결과로 나온 리스트의 원소의 개수가 같다는 것이다.
결론으로 map은 리스트의 원소들을 함수로 매핑하여, 원소의 개수가 같은 또 다른 리스트를 만드는 것이다.(1)
두번째로 reduce 가 있다.
(개인적으로 reduce는 영어 단어를 외울 때 "줄이다" 로 외워서 항상 볼 때마다 뭔가 뺄 것 같은 느낌이라 와닿지 않을 떄가 많았다.)
reduce 는 map과 마찬가지로 기본적으로 첫번째 인자로 함수와 두번째 인자로 리스트 등을 받는다.
그리고 결과로 하나의 값을 반환한다.
(함수에 따라서 하나의 리스트, 벡터 등이 반환될 수도 있기 때문에 원소들을 조합해 하나의 결과를 만들어낸다는 의미로 받아들이면 될 것 같다.)
여기서 함수는 인자가 2개인 함수만 올 수 있다.
조금 복잡하게 느껴질 수 있는데, reduce의 작동방식을 보면 이해하기 쉬울 것 같다.
=> (reduce + [1 3 5 7])
'''
(null) + 1 = 1 /* 정확히는 null 에 1을 더하진 않겠지만 나중을 위해 이렇게 표현했다. */
1 + 3 = 4
4 + 5 = 9
9 + 7 = 16
'''
=> 16
이 된다.
즉, 인자의 함수를 리스트 원소들을 하나씩 가져와서 결과를 순차적으로 반환한다.
순차적으로 실행하기 위해서 reduce의 인자로 들어가는 함수의 인자가 2개여야 하는 것이다.
그래야 하나씩 계산하고 계산한 결과를 다음 원소와 계산할 수 있으니깐.
예시를 보여줄 때 null을 썼는데, reduce 함수를 이해할 때 원소에서 하나씩 가져와서 계산한다는 의미에서 null을 사용했다.
reduce에 초기값을 줄 수 있는 경우가 있는데, 이 때와 동일하게 원칙을 사용하면 좋을 것 같아서 임의로 사용한 것이니 무시해도 좋을 것 같다.
(reduce + 10 [1 3 5 7])
'''
10 + 1 = 11
11 + 3 = 14
14 + 5 = 19
19 + 7 = 26
'''
=> 26
/* 추측 주의
reduce의 의미는 추측하기론 긴 리스트가 하나의 결과로 줄어든다는 의미에서 reduce를 사용한 게 아닐까?
아니면 여러번 써야하는 함수를 한 번만 쓸 수 있어서 줄어든다는 의미일까?
*/
다시 한 번 정리하면, reduce는
원소들을 하나씩 가져와서 함수에 적용하는 것으로, 해당 함수는 인자가 2개인 함수여야 한다. (2)
그리고 함수의 결과는 리스트의 원소와 상관없는 하나의 값이 만들어진다. (3)
개인적으로 map은 원소들의 값만 "매핑"하여 개수는 동일한 새로운 리스트를 만드는 것이고,
reduce는 여러 개의 원소들의 값을 하나씩 꺼내와 (줄어든) 새로운 값을 만드는 것이다.
라고 외우는 게 좋은 것 같다.
물론, reduce는 인자의 함수에 따라서 개수가 늘어날 수도 있긴 한데, 줄어든 값을 만들어낸다고 생각하면 외우기 쉬운 것 같다.
사용할 때 문법은 조금 다를 수 있어도, 함수의 기능자체는 다른 언어에서도 동일할 것으로 보인다.
'Daily > DIL' 카테고리의 다른 글
[실수노트] OZ parameter를 넘겼는데 값이 전달이 되지 않는다. (0) | 2019.11.07 |
---|