2. Concrete Type
Haskell에서 Concrete Type이란 해당 타입의 값을 만들 수 있는 타입을 의미합니다. 예를 들어,
아래와 같은 타입의 값은 존재할 수 있지만
Double
Int -> Char
[Int]
아래와 같은 타입의 값은 존재할 수 없습니다.
Maybe
왜냐하면, Maybe는 그 자체로 완벽한 타입이 아니라 하나의 타입을 받아 Concrete Type(Maybe
Int, Maybe Char 등)을 만들어내는 생성자기 때문이죠.
3. Kind
Kind는 Type을 분류하는 기준이라고 볼 수 있습니다. Type의 Type이라고도 얘기할 수 있겠네요.
앞에서 말한 Concrete Type이 Haskell에서는 *라는 Kind로 분류됩니다. 각각의 타입이 Haskell
에서 어떤 Kind에 속하는지 확인하려면 ghci에서 :k 명령어를 사용하면 됩니다.
Prelude> :k Int
Int :: *
Prelude> :k Int -> Int
Int -> Int :: *
Prelude> :k Maybe Int
Maybe Int :: *
Prelude> :k Maybe
Maybe :: * -> *
4. Kind
앞 슬라이드의 마지막 부분을 보면 Maybe 타입의 Kind는 * -> * 인 것을 알 수 있습니다. 이 형태는
함수의 타입과 굉장히 유사하고, 사실 의미도 비슷합니다. Maybe라는 타입은 Concrete type을 하나
인자로 받아서 Concrete Type을 생성해내는 타입 생성자라는 의미죠.
Maybe :: * -> *
Int Maybe Int
Char Maybe Char
[Int] Maybe [Int]
(Int, Int) Maybe (Int, Int)
5. Kind
Either와 같은 타입 생성자는 두 개의 타입을 인자로 받습니다. Either 타입은 아래와 같이
선언되어 있죠.
data Either a b = Left a | Right b
Either 타입의 Kind는 어떻게 될까요?
Prelude> :k Either
Either :: * -> * -> *
인자를 두 개 받는 함수의 타입과 비슷합니다.
6. Kind
타입 생성자 역시 부분 적용이 가능합니다. Either 타입 생성자에 부분 적용을 해봅시다.
Prelude> :k Either String
* -> *
Prelude> :k Either Int String
*
Kind 역시 함수의 타입 서명을 보듯이 이해하면 이해하기 쉽다는 것을 알 수 있습니다.
7. Kind
조금 더 복잡한 내용으로 들어가보죠. 아래 데이터 타입은 어떤 Kind를 가지게 될까요?
data Foo a = Bar (a Int)
Foo a라는 데이터 타입은 Bar (a Int)라는 값을 가질 수 있는 타입입니다. 여기서 a Int 부분을
통해 a라는 타입이 Int를 인자로 받아 Concrete Type을 하나 만들어내는 타입 생성자라는 것을 알
수 있습니다. 즉, a 타입은 * -> * 라는 kind가진다는 것을 알 수 있죠. 따라서 Foo 타입은
(* -> *) -> *라는 Kind를 가지게 될 것입니다. 확인해보죠.
Prelude> :k Foo
(* -> *) -> *
8. Kind
이런 kind 역시 Haskell은 모두 컴파일러가 추론해줍니다.
data Complicate a b = Complicate { field :: b a }
data KindTest a b c = KindTest { field1 :: c, field2 :: a b }
Prelude> :k Complicate
Complicate :: * -> (* -> *) -> *
Prelude> :k KindTest
KindTest :: (* -> *) -> * -> * -> *
Concrete Type만이 값을 만들 수 있다(어떤 값의 타입이 t라면, t의 kind는 반드시 *이다)라는
특징에서 추론해보면 어떻게 이런 결과가 나오는지 알 수 있습니다.
9. Kind
Kind 개념 자체는 코딩을 할 때는 전혀 필요 없습니다. 코드에서 직접 언급되는 개념이 아니며, 단지
Haskell의 타입 시스템을 이해하는 것에 좀 더 도움을 주는 개념일 뿐입니다.
다만 Haskell은 대부분의 코드가 임의 타입에 대해 일반적으로 동작하는 방식으로 이루어져있고, 또
Haskell의 각종 타입 클래스가 어떤 Kind의 타입을 대상으로 하는 건지 이해하고 쓰기 위해서도 Kind
개념을 아는 것이 좋습니다.