276
2
기본기 다지기
’로 채택하게 만드는 것이다. 이를 위해 약간 이상하고 악마적인 함수형 기능을 가능한 한 피
해야 한다. 하지만 나는 여러분이 그런 부분의 아름다움과 강력함을 인정하게 되길 바라며,
기능을 명백히 드러낼 것이다.
이번 장에서는 새로운 스칼라 개발자라면 반드시 알아두어야 할 필수적인 요소를 설명할 것이
다. 함수형 프로그래밍은 넓고 다양한 분야다. 따라서 새로운 개발자에게 필수적인
려운 주제는
16
장에서 다룰 것이다.
6.2
스칼라 함수형 프로그래밍
스칼라는 복합적인 객체
-
함수형 언어이기 때문에, 함수가 순수하도록 요구하지 않으며, 변수가
불변일 것을 요구하지도 않는다. 하지만 가능하면 그런 방식으로 코드를 작성하도록 장려한다.
우리가 이미 살펴본 것을 빠르게 정리해보자.
정수의 리스트를 반복하면서 짝수만 골라서
2
배한 다음,
reduce
사용해서 그들을 서로 곱하
축약하기 위해 가지 고차 함수를 사용했다.
//
src
/
main
/
scala
/
progscala2
/
fp
/
basics
/
hofs
-
example
.
sc
(
1 to 10
)
filter
(
_
%
2
==
0
)
map
(
_
*
2
)
reduce
(
_
*
_
)
결과는
122880
이다.
_ %
2
==
0
, _ *
2
, _ * _
함수 리터럴이라는 사실을 기억하라. 앞의 함수는 위치지정자
_
할당된 인자를 취한다.
reduce
전달된 마지막 함수는 인자를 취한다.
reduce
함수는 여러 원소를 서로 곱하기 위해 사용되었다. 즉, 그 함수는 정수의 컬렉션을 단일
값으로 ‘축약
reduce
한다.
reduce
전달한 함수는 인자를 둘 취하고, 각 인자는 _ 위치지정자에
할당된다. 인자 중 하나는 입력 컬렉션의 현재 원소고, 다른 하나는 ‘누적값’이다. 이 누적값은
최초 호출 시에는 컬렉션의 원소지만, 그다음부터는 직전에
reduce
를 호출한 결과로 얻은 값
이다 (누적값이 인자의 번째 값일지 두 번째 값일지는 구현에 따라 달라진다 ).
reduce
277
6
스칼라 함수형 프로그래밍
달할 함수에는 수행할 축약 연산의 결합 법칙성립해야 한다는 요구 조건이 있다. 곱셈이나
셈이 바로 그런 연산이다. 결합 법칙이 필요한 이유는 컬렉션 원소를 어떤 순서로 처리할지 아무
보장이 없기 때문이다!
따라서 반복 횟수를 추적하기 위한
var
변수나 축약 중인 값을 갱신할
var
변수를 사용하지
으면서도 성공적으로 모든 리스트의 원소에 대해 ‘루프’를 있었다.
6.2.1
익명 함수, 람다, 클로저
앞의 예제를 다음과 같이 바꿔보자.
//
src
/
main
/
scala
/
progscala2
/
fp
/
basics
/
hofs
-
closure
-
example
.
sc
var factor
=
2
val multiplier
=
(
i
:
Int
)
=
>
i
*
factor
(
1 to 10
)
filter
(
_
%
2
==
0
)
map multiplier reduce
(
_
*
_
)
factor
=
3
(
1 to 10
)
filter
(
_
%
2
==
0
)
map multiplier reduce
(
_
*
_
)
먼저
factor
라는 변수를 만들어서 승수로 활용한다. 또한 앞의 예제에 있는 익명 함수
_ *
2
분리해서
factor
사용하는
multiplier
라는 값에 저장한다.
multiplier
함수라는 사실에
유의하라. 스칼라에서는 함수도
1
계층값이기 때문에, 함수를 일반적인 값과 마찬가지로 정의
있다. 하지만
multiplier
하드코딩된
2
라는 대신
factor
참조한다.
factor
값을 변경하면서 같은 컬렉션에 대해 같은 코드를 실행한다. 실행은 예전과
마찬가지로
122880
이라는 값을 얻지만, 번째 실행에서는
933120
얻는다.
비록
multiplier
변경 불가능한 함수값이었지만,
factor
바뀜에 따라 함수의 동작도
뀌었다.
multiplie
r
에는 두 가지 변수
i
factor
가 들어 있다.
i
는 함수의 형식 인자
formal
parameter
다.
즉, 값은
multiplier
호출될 때마다 새로운 값에 결부
bind
된다. 하지만
factor
형식
자가 아니며, 자유 변수
free
variable
, 즉 주위를 둘러싼 영역에 있는 변수에 대한 참조다. 따라서
278
2
기본기 다지기
컴파일러는
multiplier
안의 문맥과
multiplier
안에서 지정되지 않은 변수들이 참조하는
외부 문맥을 함께 아우르는(또는 환경에 대해 닫혀 있는’ ) 클로저
closure
만든다. 따라서 클로
저는
multiplier
내의 모든 변수를 지정해준다.
이런 이유로
factor
바뀌면
multiplier
동작도 바뀐다.
multiplier
factor
참조하
며, 계산을 수행할 때마다
factor
의 현재 값을 가져온다. 어떤 함수에 아무런 외부 참조도
다면, 그냥 자신만으로도 이미 닫혀 있는 함수다. 이런 경우에는 외부 문맥이 필요 없다.
심지어
Factor
메서드 등 어떤 영역에 속한 지역 변수였거나, 다른 영역으로
multiplier
전달하는 경우에도 작동할 것이다.
Multiplier
전달하면, 안의 자유 변수
factor
전달된다.
//
src
/
main
/
scala
/
progscala2
/
fp
/
basics
/
hofs
-
closure2
-
example
.
sc
def m1
(
multiplier
:
Int
=
>
Int
)
=
{
(
1 to 10
)
filter
(
_
%
2
==
0
)
map multiplier reduce
(
_
*
_
)
}
def m2
:
Int
=
>
Int
=
{
val factor
=
2
val multiplier
=
(
i
:
Int
)
=
>
i
*
factor
multiplier
}
m1
(
m2
)
m2
를 호출해서
Int
=
>
Int
타입의 함수값을 반환받는다.
m2
는 내부의
multiplier
라는 값을
반환한다. 하지만
m2
에는
factor
라는 다른 값도 들어 있다. 이 값은
m2
에서 반환된 다음에는
영역의 밖에 있다.
그 후
m1
을 호출하면서
m2
가 반환한 함수값을 넘긴다. 여기서 비록
factor
m1
내부의 영역
에는 없지만, 출력은 예전과 마찬가지로
122880
이다.
m2
반환한 함수는 실제로는
factor
대한 참조까지 포함하는 클로저다.
개념이 약간 중복되는 자주 사용되는 용어가 가지 있다.

Get 프로그래밍 스칼라: 실용적인 스칼라 활용법을 익히는 가장 확실한 실전 바이블 (2.11.x 버전 기반) now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.