575
15
장
스칼라 타입 시스템 II
15.6
타입 람다
타입 람다
type
lambda
는 다른 함수 안에 내포된 함수와 비슷한 개념을 타입 수준에서 적용한 것이
다. 타입 람다는 맥락에 대해 너무 많은 타입 매개변수가 필요한 매개변수화한 타입이 필요한
상황에서 쓸모가 있다. 이는 타입 시스템이 제공하는 구체적인 기능이라기보다는 일종의 코딩
관용구라고 생각할 수 있다.
map
을 사용하는 예를 보자. 앞에서 봤던
reduce
와는 조금 다른 접근 방식을 택했다.
//
src
/
main
/
scala
/
progscala2
/
typesystem
/
typelambdas
/
Functor
.
scala
package progscala2
.
typesystem
.
typelambdas
import scala
.
language
.
higherKinds
trait Functor
[
A
,+
M
[
_
]]
{
//
➊
def map2
[
B
](
f
:
A
=
>
B
):
M
[
B
]
}
object Functor
{
//
➋
implicit class SeqFunctor
[
A
](
seq
:
Seq
[
A
])
extends Functor
[
A
,
Seq
]
{
def map2
[
B
](
f
:
A
=
>
B
):
Seq
[
B
]
=
seq map f
}
implicit class OptionFunctor
[
A
](
opt
:
Option
[
A
])
extends Functor
[
A
,
Option
]
{
def map2
[
B
](
f
:
A
=
>
B
):
Option
[
B
]
=
opt map f
}
implicit class MapFunctor
[
K
,
V1
](
mapKV1
:
Map
[
K
,
V1
])
//
➌
extends Functor
[
V1
,({
type λ
[
α
]
=
Map
[
K
,
α
]})#
λ
]
{
//
➍
def map2
[
V2
](
f
:
V1
=
>
V2
):
Map
[
K
,
V2
]
=
mapKV1 map
{
case
(
k
,
v
)
=
>
(
k
,
f
(
v
))
}
}
}
➊ ‘펑터
Functor
’라는 이름은 맵 연산을 제공하는 타입에 대해 널리 사용되는 이름이다. 이에 대
해서는
16
.
2
.
2
절 ‘펑터 카테고리’에서 다룰 것이다. 앞의
Reduce
타입과 달리, 이 타입은 컬렉
션을 메서드의 인자로 넘기지 않는다. 대신
map2
라는 메서드를 제공하는
Functor
클래스로 변
환하는 암시적 변환을 정의할 것이다. 여기서 ‘
2
’는 일반적인
map
메서드와의 혼동을 방지하기
576
3
부
기초를 넘어서
위해 붙인 것이다. 따라서
M
[
T
]
가 반공변일 필요는 없고, 이제는 실제로 공변적으로 정의하는 편
이 더 유용하다.
➋
Seq
와
Option
에 대한 암시적 변환을 보통 때와 같이 정의한다. 단순화를 위해 각각의
map
을
활용해서
map2
를 구현했다.
Functor
가
M
[
T
]
에 대해 공변적이기 때문에
Seq
에 대한 암시적 변
환을
Seq
의 모든 서브타입에도 사용할 수 있다.
➌ 이 예제의 핵심 부분이다.
Map
에 대한 변환을 정의한다. 여기서는 타입 매개변수를 하나가
아니라 두 개 받는다.
➍ 타입 람다를 사용해서 추가 타입 매개변수를 처리한다.
MapFunctor
에서 우리는
Map
에 대한 매핑이 키를 동일하게 유지하고, 값만 바꾼다고 ‘결정’했다.
실제의
Map
.
map
(
http
://
bit
.
ly
/
1wkYedE
) 메서드는 더 일반적이며, 키와 값을 모두 바꿀 수
있다 (실제로 여기서는 결과적으로
Map
.
mapValues
(
http
://
bit
.
ly
/
1wkYedE
)를 정의하는 셈
이다 ). 타입 람다 관용구의 구문은 조금 번잡스러워 보이며, 처음 본 사람이 이해하기란 거의
쉽지 않다. 이를 확장해서 우리가 무슨 일을 벌이고 있는지 이해해보도록 하자.
...
Functor
[
V1
,
//
➊
(
//
➋
{
//
➌
type λ
[
α
]
=
Map
[
K
,
α
]
//
➍
}
//
➎
)#
λ
//
➏
]
➊
V1
은 타입 매개변수의 목록을 시작한다.
Functor
의 두번째 타입 매개변수는 컨테이터 타입
이어야 하며, 그 컨테이너 타입 자체도 자체도 타입 매개변수를 하나 취한다.
➋ ➏번 줄에서 끝날 식을 여는 괄호다. 이 괄호는 두 번째 타입 매개변수의 정의를 시작한다.
➌ 구조적 타입을 정의하기 시작한다 (
14
.
7
절 ‘구조적 타입’을 보라 ).
➍
Map
에 대한 별명인 타입 멤버를 정의한다. 여기 사용한
λ
라는 이름은 임의로 정한 것이다 (타
입 멤버의 경우 항상 그렇다 ). 하지만
λ
를 사용하는 것이 일반적이며, 이 패턴의 이름도 여기에
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.