-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
239 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
--- | ||
title: 3장 매개변수에 의한 다형성 | ||
date: 2024-07-21 13:07:50 | ||
category: 타입으로 견고하게 다형성으로 유연하게 | ||
tags: [] | ||
draft: true | ||
--- | ||
|
||
## 3.1 제네릭 함수 | ||
|
||
- 한 개 이상의 타입 매개변수를 가지는 함수를 제네릭 함수(generic function)라고 부른다. | ||
- 대부분의 언어에서는 제네릭 함수 정의를 검사 할 때 타입 매개변수가 아무 타입이나 나타낼 수 있다고 가정한다. | ||
- 매개변수에 의한 다형성을 제공하는 대부분의 언어는 타입 인자 추론을 함께 제공한다. | ||
- 타입 인자 추론이 언제나 내가 원하는 대로 되지는 않는다는 사실을 항상 기억해야 한다. 타입 검사기가 내 프로그램을 거부한 이유를 잘 모르겠을 때는 생략한 타입 인자를 하나씩 다시 넣어 보는 것이 도움이 될 수 있다. | ||
- 제네릭 함수를 정의할 때도 타입 추론을 하는 방식 중 하나가 `힌들리-밀너 타입 추론`이다. | ||
- 타입 매개 변수를 쓰지 않아도 함수가 자동으로 제네릭 함수가 될 수 있다는 말이다. | ||
- 어떤 매개변수가 함수 안에서 특별한 능력 이 요구되지 않는 곳에서만 사용된 다면 그 매개변수의 타입은 타입 매개변수를 사용해 표현할 수 있다. 따라서 그런 매개변수가 하나라도 발견된다변 그 함수는 제네릭 함수가 된다. | ||
- 힌들리 밀너 타입 추론 대신 `렛 다형성`이라는 용어를 사용하는 데, 이는 힌툴리-밀너 타입 추론을 사용하는 대표적인 언어인 오캐멀에서 함수를 정의할 때 사용하는 키워드가 let인 데서 온 것이다. | ||
|
||
## 3.2 제네릭 타입 | ||
|
||
- 타입에 타입 매개변수를 추가하면 제네릭 타입이 된다. | ||
- 자료 구조의 타입이 대개 제네릭 타입이다. | ||
|
||
## 3.3 무엇이든 타입 | ||
|
||
- 제네릭 메서드를 대신 사용 할 수 있다고해서 무엇이든 타입의 가치가 사라지는 것은 아니다. | ||
- 제네릭 메서드를 가진 객체를 인자로 넘기기보다는 제네릭 함수를 바로 인자로 넘기는 편이 더 간결하다. 이를 가능케하는 무엇이든 타입이 요긴한 이유다. | ||
- 자바의 일급 함수와 비슷한 케이스이다. | ||
|
||
```ts | ||
// function simulate(){ | ||
// const int = randUniform([1,2,3]); | ||
// const str = randUniform(["1", "2", "3"]); | ||
|
||
// return int || str | ||
// } | ||
|
||
function simulate<T>(rand: (arr: T[]) => T): void { | ||
// Type 'number' is not assignable to type 'T'. | ||
// 'T' could be instantiated with an arbitrary type which could be unrelated to 'number' | ||
const int = rand([1, 2, 3]); | ||
// Type 'number' is not assignable to type 'T'. | ||
// 'T' could be instantiated with an arbitrary type which could be unrelated to 'number' | ||
const str = rand(['1', '2', '3']); | ||
} | ||
|
||
function randUniform<T>(arr: T[]): T { | ||
return arr[0]; | ||
} | ||
function randGeometric<T>(arr: T[]): T { | ||
return arr[0]; | ||
} | ||
|
||
const i = simulate(randUniform); | ||
console.log(i); | ||
const s = simulate(randGeometric); | ||
console.log(s); | ||
|
||
// function simulate<T>(arr: T[], rand: (arr: T[]) => T): T { | ||
// return rand(arr); | ||
// } | ||
|
||
// const i = simulate([1,2,3], randUniform); | ||
// console.log(i); | ||
// const s = simulate(["1", "2", "3"], randGeometric); | ||
// console.log(s); | ||
``` | ||
|
||
- 무엇이든 타입은 최소 타입과 비슷하다. 아무 값도 최소 타입에 속하지 않듯이 무엇이든 타입의 값을 만드는 것은 어려운 편이다. 인자가 무슨 타입 인지 모르기 때문에 인자를 가지고 할수 있는 일이 제한적이다. 인자를 그대로 반환하거나 인자를 출력하는 일 정도가 고작이다. | ||
- 무엇이든 타입에 속하는값 은 얼마 없다. 그 대신 무엇이든 타입을 사용하기는 매우 쉽다. 최소 타입의 부품을 아무 데나 넣을 수 있는 것과 비슷하다. | ||
- 무엇이든 할 수 있는 사람은 찾기 어렵다. 무슨 일을 맡기든 척척 잘 해낼 것 이다. | ||
|
||
## 3.4 무엇인가 타입 | ||
|
||
- 무엇인가 타입은 `존재 양화 타입`이라고 번역할 수도 있다. | ||
- 일반적으로 정적 타입 언어가 제공하는 기능들은 더 많은 프로그램이 문제없이 타입 검사를 통과할 수 있도록 돕는다. 반면 무엇인가 타입의 역할은 정반대다. 오히려 타입 검사를 통과할 수 있는 프로그램 이 타입 검사를 통과하지 못하도록 방해한다. 이는 보통 필요 없는 능력이다. 하지만 라이브러리를 만드는 입장에서는 라이브러리 사용자의 행동을 제약할 필요가 있다. | ||
- 무엇인가 타입은 최대 타입과 비슷하다. 아무 값이나 최대 타입의 값이 될 수 있듯이 무엇인가 타입의 값을 만드는 것 역시 쉽다. 또, 최대타입의 값을 사용 할 수 있는 곳이 거의 없는 것처럼, 무엇인가 타입의 값을 사용하는 방법 또한 제한적이다. | ||
- 무엇인가 할 수 있는 사람은 찾기 쉽다. 누구나 각자 자신이 잘하는 일이 있 다. 무엇인가 할 수 있는 사람에게는 그 사람이 잘할 수 있는 일을 찾아 줘야 한다. 아무거나 시켜서는 그 사람의 능력을 다 발휘하기 어렵다. | ||
|
||
```ts | ||
interface Timestamper<T = unknown> { | ||
init(): T; | ||
next(t: T): T; | ||
cmp(t1: T, t2: T): boolean; | ||
} | ||
|
||
class IntTimestamper implements Timestamper<number> { | ||
init(): number { | ||
return 0; | ||
} | ||
next(t: number): number { | ||
return t + 1; | ||
} | ||
cmp(t1: number, t2: number): boolean { | ||
return t1 < t2; | ||
} | ||
} | ||
|
||
class StringTimestamper implements Timestamper<string> { | ||
init(): string { | ||
return 'a'; | ||
} | ||
next(t: string): string { | ||
return t + 'a'; | ||
} | ||
cmp(t1: string, t2: string): boolean { | ||
return t1.length < t2.length; | ||
} | ||
} | ||
|
||
function create(): Timestamper<number | string> { | ||
if (Math.random() < 0.5) { | ||
return new IntTimestamper(); | ||
} else { | ||
return new StringTimestamper(); | ||
} | ||
} | ||
|
||
const t: Timestamper = create(); | ||
const ts0 = t.init(); | ||
const tsl = t.next(ts0); | ||
const bol = t.cmp(ts0, tsl); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters