여기서 "값", "유형"및 "종류"는 형식적인 의미를 갖기 때문에 일반적인 영어 사용법이나 자동차 분류와의 유사성을 고려하면 지금까지만 얻을 수 있습니다.
나의 답변은 구체적으로 Haskell의 맥락에서이 용어들의 공식적인 의미에 관한 것입니다. 이러한 의미는 수학 / CS "유형 이론"에 사용 된 의미를 기반으로합니다 (실제로 동일하지는 않지만). 따라서 이것은 "컴퓨터 과학"에 대한 좋은 답변은 아니지만 꽤 좋은 Haskell 답변으로 사용되어야합니다.
Haskell (및 기타 언어)에서는 식에 허용되는 값 의 클래스를 설명 하는 형식 을 프로그램 식 에 지정하면 도움 이됩니다. 나는 당신이 표현에 알고하는 것이 유용 할 이유를 이해하기에 충분한 사례를 본 적이 있다고 가정하자 , 변수 와 항상 유형의 값을 것 이 아니라, 말 과 각각. 기본적으로 유형을 갖는 것은 광범위한 값에서 올바르게 작동하는 표현식 / 프로그램을 작성하는 데 도움이 됩니다 .sqrt (a**2 + b**2)
a
b
Double
String
Bool
지금, 당신이 깨달을 수없는 것은 타입 시그니처에 나타나는 것과 같은 Haskell 타입입니다.
fmap :: Functor f => (a -> b) -> f a -> f b
실제로 자체적으로 유형 수준의 Haskell 하위 언어로 작성됩니다. 프로그램 텍스트 Functor f => (a -> b) -> f a -> f b
는 말 그대로이 하위 언어로 작성된 유형 표현식 입니다. 부수 언어 (예를 운영자가 포함 ->
이 언어에서 오른쪽 연관 중위 연산자), 변수 (예를 들어 f
, a
및 b
) 다른 하나의 유형의 발현 및 "적용"(예 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
종류 갖는 * -> *
변수 a
와 b
종류가 *
; 내장 연산자 ->
는 종류가 있습니다 * -> * -> *
( *
왼쪽 에는 종류 가 있고 오른쪽에는 종류가 있으며 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의 타입 시스템은 이미 종료되지 않았기 때문에 역설로 가득 차 있으므로 크게 고려되지 않습니다.