577
15
스칼라 타입 시스템 II
서 온 것이다.
1
타입에는 자체 타입 매개변수인
α
가 있다(이 역시 임의로 정한 것이다 ). 이
경우에는
Map
타입을 지정하기 위해
α
사용한다.
구조적 타입 정의를 끝낸다.
줄에서 시작한 식을 끝내면서, 구조적 타입에 있는
λ
대한 타입 투영을 사용한다
(
15
.
3
‘타입 투영’을 기억하라).
λ
이후에 올 코드에서 추론될 내포된 타입 매개변수를
Map
대한 별명이다.
따라서 타입 람다는
Functor
가 지원하지 못하는,
Map
에 필요한 추가 타입 매개변수를 처리해
준다.
α
이어지는 코드에서 추론된다.
λ
α
대해 명시적으로 다시 참조할 필요는 없다.
다음 스크립트는 코드의 동작을 보여준다.
//
src
/
main
/
scala
/
progscala2
/
typesystem
/
typelambdas
/
Functor
.
sc
import scala
.
language
.
higherKinds
import progscala2
.
typesystem
.
typelambdas
.
Functor
.
_
List
(
1
,
2
,
3
)
map2
(
_
*
2
)
//
List
(
2
,
4
,
6
)
Option
(
2
)
map2
(
_
*
2
)
//
Some
(
4
)
val m
=
Map
("
one
"
-
>
1
,
"
two
"
-
>
2
,
"
three
"
-
>
3
)
m map2
(
_
*
2
)
//
Map
(
one
-
>
2
,
two
-
>
4
,
three
-
>
6
)
타입 람다 관용구가 자주 필요하지는 않을 것이다. 하지만 그것은 여기서 설명한 문제를 해결
하고 싶은 경우에 유용한 기법이다. 스칼라의 향후 버전에는 어쩌면 이런 관용구와 비슷한 더
단순한 구문이 들어갈지도 모르겠다.
15.7
자기 재귀 타입:
F
-
바운드 다형성
기술적으로는
F
-
바운드 다형 타입
F
-
bounded
polymorphic
type
이라 불리는 자기 재귀 타입은 자기
신을 참조하는 타입을 말한다. 전형적인 예는 모든 자바 열거형의 기반인
Enum
(
http
://
bit
.
ly
/
1wN98XJ
) 추상 클래스다. 선언은 다음과 같다.
1
주_ 물론
L
과같은아스키알파벳이키보드로입력하기더편하다.
578
3
기초를 넘어서
public abstract class Enum
<
E extends Enum
<
E
>>
extends Object
implements Comparable
<
E
>
,
Serializable
대부분의 자바 개발자는
Enum
<
E
extends
Enum
<
E
>>
라는 구문을 혼란스러워 할 것이다. 하지
이런 구문에는 가지 중요한 이점이 있다. 그중 하나를
Comparable
<
E
>
있는
compareTo
메서드의 시그니처에서 있다.
int compareTo(E obj)
같은 타입에 정의된 열거값 중 하나가 아닌 객체를
compareTo
에 넘기는 것은 컴파일 오류다.
이를
JDK
Enum
서브타입 가지인
java
.
util
.
concurrent
.
TimeUnit
(
http
://
bit
.
ly
/
108cKsx
)이나
java
.
net
.
Proxy
.
Type
(
http
://
bit
.
ly
/
1yMiS5H
)예제와 비교해보자.
scala
>
import java
.
util
.
concurrent
.
TimeUnit
scala
>
import java
.
net
.
Proxy
.
Type
scala
>
TimeUnit
.
MILLISECONDS compareTo TimeUnit
.
SECONDS
res0
:
Int
=
-
1
scala
>
Type
.
HTTP compareTo Type
.
SOCKS
res1
:
Int
=
-
1
scala
>
TimeUnit
.
MILLISECONDS compareTo Type
.
HTTP
<
console
>
:
11
:
error
:
type mismatch
;
found
:
java
.
net
.
Proxy
.
Type
(
HTTP
)
required
:
java
.
util
.
concurrent
.
TimeUnit
TimeUnit
.
MILLISECONDS compareTo Type
.
HTTP
^
스칼라에서는 재귀적인 타입을 사용해서 반환 타입이 호출한 타입과 동일한 메서드를 편하게
정의할 수 있다. 심지어 타입 계층구조 안에서 이런 타입의 정의가 가능하다.
make
메서드가
579
15
스칼라 타입 시스템 II
메서드가 정의된
Parent
타입의 인스턴스가 아니라 메서드를 호출한 객체와 같은 타입의
스턴스를 반환해야 하는 아래 예제를 보자.
//
src
/
main
/
scala
/
progscala2
/
typesystem
/
recursivetypes
/
f
-
bound
.
sc
trait Parent
[
T
<
:
Parent
[
T
]]
{
//
def make
:
T
}
case class Child1
(
s
:
String
)
extends Parent
[
Child1
]
{
//
def make
:
Child1
=
Child1
(
s
"
Child1
:
make
:
$
s
")
}
case class Child2
(
s
:
String
)
extends Parent
[
Child2
]
{
def make
:
Child2
=
Child2
(
s
"
Child2
:
make
:
$
s
")
}
val c1
=
Child1
("
c1
")
//
c1
:
Child1
=
Child1
(
c1
)
val c2
=
Child2
("
c2
")
//
c2
:
Child2
=
Child2
(
c2
)
val c11
=
c1
.
make
//
c11
:
Child1
=
Child1
(
Child1
:
make
:
c1
)
val c22
=
c2
.
make
//
c22
:
Child2
=
Child2
(
Child2
:
make
:
c2
)
val p1
:
Parent
[
Child1
]
=
c1
//
p1
:
Parent
[
Child1
]
=
Child1
(
c1
)
val p2
:
Parent
[
Child2
]
=
c2
//
p2
:
Parent
[
Child2
]
=
Child2
(
c2
)
val p11
=
p1
.
make
//
p11
:
Child1
=
Child1
(
Child1
:
make
:
c1
)
val p22
=
p2
.
make
//
p22
:
Child2
=
Child2
(
Child2
:
make
:
c2
)
Parent
는 재귀적 타입이다. 이 구문은 앞의 자바
Enum
에서 봤던 것과 같은 역할을 하는 스
칼라 구문이다.
파생 타입은
X
extends
Parent
[
X
]
라는 관용구를 따라야 한다.
스크립트의 아래쪽에서 만들어낸 여러 값에 대한 타입 시그니처를 살펴보라. 예를 들어
p22
비록
Parent
참조를 통해
make
호출했지만
Child2
타입이다.

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.