2

질문컴파일러가 제네릭 형식 변수의 이름이 다른 두 개의 동일한 서명을 다른 형식으로 식별하는 이유는 무엇입니까?

val of_bindings : (key * '_a) list -> '_a t 
val of_bindings : (key * 'a) list -> 'a t 

다른 서명은?

상황

좀지도 확장 구현이 있습니다

MAPEXT.ml :

module type T = sig 
    include Map.S  
    val of_bindings : (key * 'a) list -> 'a t 
    end 

mapExt.mli :

module Make (Key : Map.OrderedType) 
    : MAPEXT.T with type key = Key.t 

mapExt.ml :

module Make (Key : Map.OrderedType) = struct 
    include Map.Make (Key) 
    let of_bindings = 
     let rec of_bindings acc = 
     function | (k, v) :: t -> of_bindings (add k v acc) t 
       | []   -> acc in 
     of_bindings empty 
    end 

컴파일러 내가 제네릭 형식 변수의 이름은 단지 다른 신호에 대한 중요하지 않다 생각 ocamlopt -c MAPEXT.ml mapExt.mli mapExt.ml

Error: The implementation mapExt.ml does not match the interface mapExt.cmi: ... At position module Make(Key) : Values do not match: val of_bindings : (key * '_a) list -> '_a t is not included in val of_bindings : (key * 'a) list -> 'a t File "mapExt.ml"

의 결과로 나에게 오류를 준 유형. 하지만 지금부터는 다른 의미를 가진 것처럼 보입니다.

이 코드를 컴파일하는 방법을 피하려면 어떻게해야합니까?

관련 : What is the difference between 'a and '_l?

+1

"부분 적용을 통해 얻은 기능이 다형성이 아니므로"https://ocaml.org/learn/faq.html#Typing 섹션을 참조하십시오. – camlspotter

답변

3

이것은 단지 다른 이름 (당신이 문제가되지 않는 형태 변수의 올바른 이름입니다)이 아닙니다. 형식 변수 이름이 '_ 시퀀스로 시작하면이 형식 변수가 약한 다형성이라고 말하는 컴파일러 방식입니다. 간단히 말하면, 그것은 다형성이 전혀 없으며, 귀하의 가치가 일반적인 것이 아님을 나타냅니다. 기본적으로 유형 변수는 값의 유형이 다양하다는 것을 나타냅니다. 예를 들어 'a listint list, string list 등과 같이 유형 범위에 속할 수있는 값입니다. 즉, 유형 변수는 무한 범위를 나타냅니다 즉, 모든 표기법에 해당합니다. 약한 타입의 변수는 많은 타입에 걸쳐서 범위가 없기 때문에 하나의 타입에 대해서만 적용됩니다. 즉, 타입이 '_a list이라면 타입이 x (하나만 존재합니다)이라는 의미입니다. 가치 유형은 x list입니다. 컴파일러가 형식을 아직 모르는 것입니다. 예의의 문제로, 컴파일러는 우리에게 여분의 위도를 주며 형식 오류를주지 않습니다.

형식 변수가 모든 개념에 대해 일반화되지 않고 존재 표기법을 따르는 이유는 OCaml과 함수 응용 프로그램의 변경 가능성을 숨 깁니다. 일반적인 규칙은 컴파일러가 값 계산에 관찰 가능한 부작용이 없다는 것을 증명할 수 없다면 값이 일반화되지 않고 모든 유형 변수가 약하게 남아 있다는 것입니다. 부분 함수 응용에서 얻은 값은 임의 계산의 결과이므로 컴파일러는 계산이 부작용을 가질 수 있다고 보수적으로 가정하고 형식을 일반화하지 않습니다. 이것은 value restriction라고하며 OCaml 유형 시스템의 기능입니다.이를 처리하는 일반적인 방법은 모든 매개 변수를 추가하여 값이 부분 응용 프로그램에 의해 생성되지 않고 구문 적 값 (컴파일하는 동안 계산 (결정)되는 값의 클래스)이 될 수 있도록하는 것입니다. 이 메커니즘의 멋진 이름은 Eta Expansion입니다.