유형과 종류의 차이점은 무엇입니까?


26

나는 프로그래밍 언어학 Haskell을 배우고 있으며, a type와 a 의 차이점에 대해 내 머리를 감싸려고합니다 kind.

내가 이해 한대로 a kind is a type of type. 예를 들어, a ford is a type of cara car is a kind of vehicle.

이것에 대해 생각하는 좋은 방법입니까?

왜냐하면, 나의 두뇌가 현재 연결되어있는 방식 ford is a **type** of car이지만 car is a **type** of vehicle, 동시에 car is a **kind** of vehicle. 즉 용어 typekind상호 교환 가능합니다.

누구든지 이것에 대해 밝힐 수 있습니까?


6
방금 Stack Overflow의 게시물 에서이 토론으로 이어졌습니다. 내가 자세히 대답 할 자격이 있는지는 확실하지 않습니다. 그러나 "유형"과 "종류"라는 용어는 영어로 된 의미와 의미를 연관 시키려고 할 때 너무 문자 그대로입니다 (실제로 동의어 인 경우). ). 기술 용어로 취급해야합니다. "유형"은 모든 프로그래머가 잘 이해하고 있습니다.이 개념은 Javascript와 같이 약한 유형의 언어라도 모든 언어에 중요하기 때문에 "유형"은 Haskell에서 "유형 유형"에 사용되는 기술 용어입니다. 그게 전부입니다.
로빈 지그 먼드

2
@RobinZigmond : 당신은 이것들이 기술적 인 용어라는 것이 맞습니다. 그러나 그것들은 Haskell보다 더 광범위하게 사용됩니다. 이 질문에 걸렸던 스택 오버플로 토론으로 돌아가서 어쩌면?
Andrej Bauer

@AndrejBauer 나는 그들이 Haskell 외부에서 사용되지 않았다고 결코 말하지 않았다. 확실히 "type"은 본질적으로 모든 언어에서 사용된다. 나는 실제로 Haskell 외부의 "종류"를 본 적이 없지만 Haskell은 내가 아는 유일한 기능적 언어이며 다른 곳에서는 사용되지 않는다고 말하지 않도록주의를 기울였습니다. 하스켈. (그리고 요청에 따라 링크는 여기에 있습니다 )
Robin Zigmond

ML 계열 언어도 표준 ML 및 OCaml과 같은 종류가 있습니다. 그것들은 그 이름으로 명시 적으로 노출되지 않습니다. 그것들은 시그니처 로 나타나며 , 그들의 요소는 구조 라고 불립니다 .
Andrej Bauer

1
보다 정확한 영어 비유는 포드는 자동차의 한 유형이고 자동차는 한 유형의 차량이지만 자동차 유형과 차량 유형은 모두 같은 종류입니다 : 명사. 빨간색은 자동차 색상의 유형이고 RPM은 자동차 성능 지표의 유형이며 둘 다 같은 종류입니다 : 형용사.
slebetman

답변:


32

여기서 "값", "유형"및 "종류"는 형식적인 의미를 갖기 때문에 일반적인 영어 사용법이나 자동차 분류와의 유사성을 고려하면 지금까지만 얻을 수 있습니다.

나의 답변은 구체적으로 Haskell의 맥락에서이 용어들의 공식적인 의미에 관한 것입니다. 이러한 의미는 수학 / CS "유형 이론"에 사용 된 의미를 기반으로합니다 (실제로 동일하지는 않지만). 따라서 이것은 "컴퓨터 과학"에 대한 좋은 답변은 아니지만 꽤 좋은 Haskell 답변으로 사용되어야합니다.

Haskell (및 기타 언어)에서는 식에 허용되는 의 클래스를 설명 하는 형식 을 프로그램 식 에 지정하면 도움 이됩니다. 나는 당신이 표현에 알고하는 것이 유용 할 이유를 이해하기에 충분한 사례를 본 적이 있다고 가정하자 , 변수 와 항상 유형의 값을 것 이 아니라, 말 과 각각. 기본적으로 유형을 갖는 것은 광범위한 값에서 올바르게 작동하는 표현식 / 프로그램을 작성하는 데 도움이 됩니다 .sqrt (a**2 + b**2)abDoubleStringBool

지금, 당신이 깨달을 수없는 것은 타입 시그니처에 나타나는 것과 같은 Haskell 타입입니다.

fmap :: Functor f => (a -> b) -> f a -> f b

실제로 자체적으로 유형 수준의 Haskell 하위 언어로 작성됩니다. 프로그램 텍스트 Functor f => (a -> b) -> f a -> f b는 말 그대로이 하위 언어로 작성된 유형 표현식 입니다. 부수 언어 (예를 운영자가 포함 ->이 언어에서 오른쪽 연관 중위 연산자), 변수 (예를 들어 f, ab) 다른 하나의 유형의 발현 및 "적용"(예 f a되어 f적용 a).

많은 언어에서 표현식 값의 클래스를 설명하기 위해 프로그램 표현식에 유형을 지정하는 것이 어떻게 도움이 되었습니까? 이 유형 수준의 하위 언어에서 표현식은 ( 값이 아닌 ) 유형으로 평가되며, 표현 이 허용되는 유형 의 클래스를 설명하기 위해 유형을 유형 표현식에 지정하는 것이 도움 이됩니다. 기본적으로 갖는 종류의 것은 넓은 범위에 걸쳐 제대로 작동 형 식을 서면으로 우리를 도와 유형 .

그래서, 값은 에있는 유형 으로 유형 에있는 종류유형은 우리가 작성하는 데 도움 가치 있는 동안 -level 프로그램 종류는 우리가 작성하는 데 도움 유형 -level 프로그램.

이런 종류의 모습은 무엇입니까? 글쎄, 타입 시그니처를 생각해 보자.

id :: a -> a

유형 표현식이 경우 a -> a유효합니다, 어떤 종류의유형 우리는 변수 허용해야 a될? 글쎄, 타입 표현식 :

Int -> Int
Bool -> Bool

유형이 유효 Int하고 Bool분명히 올바른 종류 입니다. 그러나 더 복잡한 유형은 다음과 같습니다.

[Double] -> [Double]
Maybe [(Double,Int)] -> Maybe [(Double,Int)]

유효 해 보인다. 실제로 id함수 를 호출 할 수 있어야하기 때문에

(a -> a) -> (a -> a)

좋아 보인다. 그래서, Int, Bool, [Double], Maybe [(Double,Int)],와 a -> a같은 모든 모양 유형 권리의 종류 .

다시 말해, 한 종류 만있는 것처럼 보이고 *유닉스 와일드 카드처럼 부르고 모든 유형 은 같은 종류 * 의 이야기 끝을가집니다.

권리?

글쎄요 그것은 Maybe모두 그 자체로 유효한 유형 표현식 Maybe Int(유사한 방식 sqrt으로 sqrt 25) 만큼 유효한 표현식 입니다. 그러나 다음 유형 표현식은 유효하지 않습니다.

Maybe -> Maybe

반면, 때문에 Maybe형식의 표현이며, 그것은 나타내지 않는 종류의유형 값을 가질 수 있습니다. 그래서, 그건 우리가 정의하는 방법 *- 그것은의 종류의유형 값이; 이 같은 "완료"유형을 포함 Double또는 Maybe [(Double,Int)]제외가 불완전, 가치없는 유형은 좋아하지만를 Either String. 간단히하기 위해, *이 용어는 "콘크리트 유형" 이라고 부르지 만,이 용어는 보편적이지 않으며 "콘크리트 유형"은 C ++ 프로그래머와 매우 다른 의미를 가질 수 있습니다.

이제, 타입 표현식에서 a -> a, 한 유형으로 a종류 * (콘크리트 유형의 종류), 타입 식의 결과는 a -> a또한종류 * (즉, 콘크리트 종류의 종류).

그래서, 어떤 종류의유형이 있다 Maybe? 음, Maybe또 다른 구체적인 유형을 생성하기 위해 구체적인 유형에 적용 할 수 있습니다. 그래서, Maybe소요 타입 수준의 기능과 같은 작은처럼 보이는 유형종류 * 와 리턴 타입종류 * . 우리는 갔다 값 레벨 기능이 있다면 유형 Int 및 반환 유형을 Int , 우리는 그것을 줘야 할 것 타입의 서명을 Int -> Int이렇게 비유로 우리가 제공해야합니다, 종류의 서명을 . GHCi는 다음에 동의합니다.Maybe* -> *

> :kind Maybe
Maybe :: * -> *

다시 돌아 가기 :

fmap :: Functor f => (a -> b) -> f a -> f b

이러한 유형의 서명에서 변수 f종류 갖는 * -> *변수 ab종류가 *; 내장 연산자 ->는 종류가 있습니다 * -> * -> *( *왼쪽 에는 종류 가 있고 오른쪽에는 종류가 있으며 kind도 반환합니다 *). 이것과 종류의 추론의 규칙에서, 당신은 그 추론 할 수 a -> b종류의 유효한 유형 *, f a그리고 f b종류의 유효한 유형은 또한 *, 및 (a -> b) -> f a -> f b종류의 유효한 유형입니다 *.

다시 말해, 컴파일러는 형식 표현식 (a -> b) -> f a -> f b을 "종류 검사"하여 올바른 유형의 변수에 유효한지 확인하는 것과 동일한 유형 sqrt (a**2 + b**2)의 변수에 대해 올바른 유형 변수에 유효한지 확인할 수 있습니다.

"유형"과 "종류"에 대해 별도의 용어를 사용하는 이유 (즉, "유형 유형"에 대해 이야기하지 않음)는 대부분 혼란을 피하기위한 것입니다. 위 의 종류종류 와 매우 다르게 보이며 적어도 처음에는 상당히 다르게 행동하는 것 같습니다. (예를 들어, 모든 "정상적인"유형이 같은 종류 *이고 다른 유형 a -> b*아니라는 생각에 머리를 감쌀 때까지 시간이 걸립니다 * -> *.)

이 중 일부는 또한 역사적입니다. GHC Haskell이 발전함에 따라 가치, 유형 및 종류의 구별이 흐려지기 시작했습니다. 요즘에는 값을 유형으로 "승격"할 수 있으며 유형과 유형은 실제로 동일합니다. 따라서 현대 Haskell에서 값은 유형과 ARE 유형 (거의)을 가지며 유형의 유형은 더 많은 유형입니다.

@ user21820은 "유형과 종류는 실제로 같은 것"에 대한 추가 설명을 요청했습니다. 현대 GHC Haskell (버전 8.0.1부터)에서 좀 더 명확하게 말하면 유형과 종류는 대부분의 컴파일러 코드에서 균일하게 처리 됩니다. 컴파일러는 값 유형 또는 유형 유형에 대해 각각 불평하는지에 따라 "유형"과 "종류"를 구별하기 위해 오류 메시지를 작성합니다.

또한 확장 기능이 활성화되어 있지 않으면 표면 언어로 쉽게 구별 할 수 있습니다. 예를 들어, 유형 (값)은 구문 (예 : 유형 서명)으로 표현되지만 유형 (유형)은 완전히 암시 적이며 명시적인 구문은 어디에도 없습니다.

그러나 적절한 확장을 설정하면 유형과 종류의 구분이 크게 사라집니다. 예를 들면 다음과 같습니다.

{-# LANGUAGE GADTs, TypeInType #-}
data Foo where
  Bar :: Bool -> * -> Foo

여기서는 Bar(값과 유형) 유형입니다. 유형으로, 종류는 Bool -> * -> Foo종류 Bool( 종류 이지만 종류)와 종류 를 취하고 종류 *를 생성하는 유형 수준 함수입니다 Foo. 그래서:

type MyBar = Bar True Int

올바르게 종류를 확인하십시오.

@AndrejBauer가 그의 답변에서 설명했듯이, 유형과 종류를 구별하지 못하는 것은 안전하지 않습니다. 유형 / 종류 *자체 (현대 Haskell의 경우) 인 유형 / 종류를 갖는 것은 역설을 초래합니다. 그러나 Haskell의 타입 시스템은 이미 종료되지 않았기 때문에 역설로 가득 차 있으므로 크게 고려되지 않습니다.


"유형과 종류가 실제로 같은 것"이라면, 그 유형 type은 그 type자체 일 뿐이며 전혀 필요가 없습니다 kind. 그렇다면 차이점은 정확히 무엇입니까?
user21820

1
@ user21820,이 문제를 해결할 수있는 메모를 끝에 추가했습니다. 짧은 대답 : 현대 GHC Haskell 에는 실제로 구별이 없습니다 .
KA Buhr

1
좋은 답변입니다. 공유해 주셔서 감사합니다. 잘 쓰여지고 개념을 점진적으로 소개합니다-몇 년 동안 Haskell을 쓰지 않은 사람으로서 매우 감사합니다!
ultrafez

@KABuhr : 추가 된 비트에 감사드립니다!
user21820

19

집합 이론에서 집합과 클래스의 차이점에 대해 알고 있다면 문제를

type:kind=set:class.
로 생각하면 도움이 될 수 있습니다 . 그렇지 않은 경우, 종류를 "큰"또는 "높은"유형으로 생각할 수 있으며, 요소가 유형일 수도 있고 어떤 방식으로 유형을 포함 할 수도 있습니다. 예를 들면 다음과 같습니다.

  • Bool 유형입니다
  • Type 요소는 유형이기 때문에 종류입니다
  • Bool -> Int 유형입니다
  • Bool -> Type 요소는 유형을 반환하는 함수이기 때문에 종류입니다
  • Bool * Int 유형입니다
  • Bool * Type 그것의 요소들이 한 구성 요소와 한 쌍의 유형이기 때문에 종류입니다

U0U1U2U0BoolNatNatNatU1U0BoolU0U0U0Un+1UnUn×

U0U1U0U1U0**U_1


2
나는 (GHC) Haskell이 우주의 개념을 가지고 있다고 생각하지 않습니다. Type :: Type공리입니다. "유형"과 "종류"의 구별은 전적으로 인간의 언어로되어 있습니다. True, 유형을 가지고 Bool, 그리고 Bool유형이 Type자체 유형이, Type. 유형 유형 엔터티 유형임을 강조하기 위해 유형을 일종이라고 부르는 경우도 있지만 Haskell에서는 유형일뿐입니다. 우주가 실제로 COQ처럼 존재하는 시스템에서, 다음 "타입"하나의 우주와 다른 "종류"를 참조 할 수 있습니다,하지만 우리는 일반적으로 무한히 많은 우주를 원한다.
HTNW

1
구별은 "인간 언어"가 아니라 기본 유형 시스템의 공식적인 구별입니다. Type :: Type유형과 종류를 구별하고 구별하는 것이 가능합니다 . 또한 Type :: TypeHaskell에서 어떤 코드 조각을 보여줍 니까?
Andrej Bauer

1
나는 또한 *Haskell에서 일종의 우주 라고 말합니다 . 그들은 그것을 그렇게 부르지 않습니다.
Andrej Bauer

3
@AndrejBauer Type에서 Data.Kinds*해야 동의어. 처음에 우리 *는 기본 요소 로만 사용 했지만 현재 GHC.Types.Type는 내부 모듈에서 내부적으로 정의되어 GHC.Types있으며로 정의되어 type Type = TYPE LiftedRep있습니다. 나는 TYPE일종의 패밀리 (리프트 타입, 언 박스 타입 등)를 제공하는 진정한 프리미티브 라고 생각 합니다. 여기서 "무의미한"복잡성의 대부분은 실제 유형 이론적 이유가 아니라 일부 저수준 최적화를 지원하는 것입니다.

1
요약하려고합니다. 경우 v값이며, 다음은 유형이 있습니다 v :: T. T유형 인 경우 유형이 T :: K있습니다. 유형의 유형을 종류라고합니다. TYPE rep단어가 흔하지는 않지만 보이는 유형을 정렬이라고 할 수 있습니다. IFF가 T :: TYPE rep되는 Ta의 RHS에 표시 할 수있는 ::. 단어 "종류"여기에 미묘한 차이가 있습니다 KT :: K하지의 일종이지만, v :: K이 같은 비록, K. " K종류가 일종 인 경우 종류"라고도 ::할 수 있습니다. 그러므로 나의 "인간 구별"입장.
HTNW

5

값은 특정 당신이 당신의 차도에 앉아 것을 거기에 1만9천2백6마일 2011 포드 머스탱 빨간색과 같다.

비공식적으로 그 특정 가치는 여러 유형을 가질 수 있습니다 . 머스탱, 포드, 자동차, 그리고 자동차이며, 다른 많은 유형 중에서도 여러분이 만들 수있는 많은 것들 ( "사물 유형") "귀하의 것"또는 "빨간색의 것"또는 ...).

Haskell에서는 1 차 근사 (GADT가이 속성을 깨뜨리고 숫자 리터럴과 OverloadedStrings 확장에 대한 마술이 조금 모호합니다)에 값이 비공식적 인 "유형"대신 하나의 주요 유형을 가지게됩니다. stang. 42은이 설명을 위해 IntHaskell에 "숫자"또는 "짝수 정수"에 대한 유형이 없습니다. 대신 하나를 만들 수는 있지만에서 분리 된 유형이됩니다 Int.)

이제 "무스탕"은 "자동차" 의 하위 유형일 수 있습니다 . 머스탱 인 모든 값은 자동차이기도합니다. 그러나 - 또는이 하스켈의 용어를 사용하려면, 종류 "머스탱"의는 "차"가 아닙니다. "무스탕 (Mustang)"유형은 차도에 주차하거나 운전할 수있는 것이 아닙니다. "무스탕 (Mustang)"은 명사, 범주 또는 유형일뿐입니다. 그것들은 비공식적 으로 "무스탕" 의 종류 입니다.

(다시 말하면, Haskell은 각 유형 수준의 물건에 대해 하나의 종류 만 인식합니다. 따라서 Int친절 *하고 다른 종류 Maybe는 없습니다. 친절 * -> *하고 다른 종류는 없습니다. 그러나 직관은 여전히 ​​유지해야합니다 : 42is Int, 당신은 Int그것으로 y 일을 할 수 있습니다 . 추가하고 빼는처럼 Int자체 것은 아니다 Int; 같은 그런 수는 없다 Int + Int당신은 비공식적으로 사람들이 그 말을들을 수 있습니다. IntA는 Num하는 사람들이 있다는 것을 의미한다, 예를Num유형에 대한 유형 클래스 Int-이게 같은 일을하지 않습니다 그 말을 Int가지고 종류 Num . Int하스켈에서 철자 종류의 "유형"을 가지고 있습니다 *.)

그래서 모든 비공식적 인 "유형"은 명사 나 범주가 아닌가? 모든 유형이 같은 종류입니까? 너무 지루하다면 왜 종류에 대해 이야기합니까?

이것은 영어 비유가 조금 어두워 질 수있는 곳이지만, 나에게 견딜 것입니다. 누군가 당신을 "소유자"라고 불렀다면 그것은 전혀 말이되지 않을 것입니다. 그러나 누군가가 당신을 "자동차 소유자"라고 불렀다면, 그들이 의미하는 바를 이해할 수있었습니다.

"소유자"는 "자동차"와 같은 종류를 갖지 않습니다 . 자동차에 대해 이야기 할 수는 있지만이 영어 버전의 영어 버전에서는 소유자에 대해 이야기 할 수 없습니다. "자동차 소유자"에 대해서만 이야기 할 수 있습니다. "소유자"는 "명사"(예 : "car")와 같은 종류의 "명사"에 적용되는 경우에만 "명사"를 생성합니다. 우리는 "소유자"의 종류가 "명사-> 명사"라고 말할 것입니다. "소유자"는 명사를 가져 와서 다른 명사에서 생성하는 함수와 같습니다. 그러나 그것은 명사 자체가 아닙니다.

"car owner"는 "car"의 하위 유형이 아닙니다. 자동차를 받거나 돌려주는 기능이 아닙니다! "자동차"와는 완전히 별개의 유형입니다. 그것은 어느 시점에서 특정 금액의 돈을 가지고 그 돈을 딜러에게 가져간 두 팔과 두 다리로 가치를 설명합니다. 4 개의 바퀴와 페인트 작업이있는 값은 설명하지 않습니다. 또한 "자동차 소유자"와 "개 소유자"는 서로 다른 유형이므로 한 가지로 할 수있는 것은 다른 것에 적용되지 않을 수 있습니다.

우리가 말을 할 때 (마찬가지로, Maybe종류가 * -> *하스켈에서, 우리는 공식적으로 (무의미의 의미, 비공식적으로 우리 "는이 문제에 대해 얘기에 모든 시간을) 할 Maybe."대신, 우리는 할 수 있습니다 Maybe Int또는를 Maybe String사람들은의 일이기 때문에, 종류 *.)

따라서 종류에 대해 이야기하는 모든 요점은 "소유자"와 같은 단어에 대한 추론을 공식화하고 "완전히 구성되고"무의미하지 않은 유형의 값만 취하도록 강제하는 것입니다.


1
나는 당신의 비유가 잘못되었다고 말하지는 않지만 그것이 혼동을 일으킬 수 있다고 생각합니다. Dijkstra는 유추에 대한 단어를 가지고 있습니다. 구글 "정말로 컴퓨팅 과학을 가르치는 잔인함에".
라파엘 카스트로

내 말은, 자동차 비유가 있고, 자동차 비유가 있다는 것입니다. 형식적 유형 시스템을 설명하는 방법으로 내재적 유형 구조를 자연 언어로 강조 표시하는 것은 확실하지 않습니다. 프로그램이하고 싶은 것.
user11228628

1

내가 이해하는 것처럼 종류는 유형의 유형입니다.

그렇습니다. 그것이 의미하는 바를 살펴 봅시다. Int또는 Text콘크리트 종류가 있지만, Maybe a입니다 추상적 인 유형입니다. a예를 들어 특정 변수 (또는 값 / 표현 / 무엇이든) 에 대해 원하는 특정 값을 결정할 때까지 구체적인 유형이되지 않습니다 Maybe Text.

우리는 말 Maybe aA는 타입 생성자 가 하나의 구체적인 유형 (예를 취하는 함수처럼 때문에 Text)와 (구체적인 형식을 반환 Maybe Text이 경우). 그러나 다른 형식 생성자는 구체적인 형식을 반환하기 전에 더 많은 "입력 매개 변수"를 사용할 수 있습니다. 예를 들어 콘크리트 유형 ( )을 구성하기 전에 Map k v두 가지 콘크리트 유형 (예 : IntText)을 사용해야합니다 Map Int Text.

따라서 Maybe aand List a타입 생성자는 우리가 * -> *(하스켈 함수 시그니처와 유사하게) 표시하는 동일한 "서명"을 가지는데 , 하나의 구체적인 유형을 제공하면 구체적인 유형을 뱉기 때문입니다. 우리는 유형과의 "종류"이 전화 MaybeList같은 종류가 있습니다.

구체적 타입은 kind라고하며 *, Map 예제는 * -> * -> *구체적 타입을 출력하기 전에 두 가지 타입의 콘크리트 입력을 입력으로 받기 때문에 친절 합니다.

당신은이 볼 수있는 대부분 단지 우리가 타입 생성자에 전달하는 것이 "매개 변수"의 수에 대해 - 우리는 종류 끝낼 수 있지만, 우리는 또한 타입 생성자는 타입 생성자 안에 중첩받을 수 있음을 깨닫게 같은 모습 * -> (* -> *) -> *예를 들어, .

Scala / Java 개발자 인 경우이 설명이 도움이 될 수도 있습니다. https://www.atlassian.com/blog/archives/scala-types-of-a-higher-kind


이것은 정확하지 않습니다. Haskell에서 우리는 Maybe a에 대한 동의어 forall a. Maybe a, polymorphic 유형의 종류 *Maybemonomorphic 유형의 종류를 구별 * -> *합니다.
b0fh
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.