유형 오류 이해 :“예상 서명 int*int-> int이지만 int*int-> int를 얻었습니다.”

StackOverflow https://stackoverflow.com/questions/324612

  •  11-07-2019
  •  | 
  •  

문제

댓글 스티브 예지'에스 게시하다 ~에 대한 서버 측 JavaScript 언어로 유형 시스템의 장점을 논의하기 시작했습니다. 논평 설명 :

... 예 다음과 같은 물건을 얻을 수있는 스타일 시스템 :

expected signature Int*Int->Int but got Int*Int->Int

함수 정의 (또는 2?)와 해당 오류가 발생하는 함수 호출의 예를 제시 할 수 있습니까? 대규모 프로그램에서 디버깅하기가 매우 어려울 것 같습니다.

또한 비슷한 오류를 보았을 수도 있습니다. 미란다? (나는 15 년 동안 그것을 사용하지 않았으므로 내 기억에 대한 나의 기억은 모호합니다)

도움이 되었습니까?

해결책

나는 소금 한 덩어리로 정적 타이핑에 대한 Yegge (그리고 Ola Bini의) 의견을 받아 들였습니다. 정적 타이핑이 제공하는 내용에 감사한다면 선택한 프로그래밍 언어의 유형 시스템이 어떻게 작동하는지 알게됩니다.

IIRC, ML은 튜플의 '*'구문을 사용합니다.u003Ctype> *u003Ctype> 두 가지 요소가있는 튜플 유형입니다. 따라서 (1, 2) int * int 유형이 있습니다.

Haskell과 ML 모두 기능 -> 기능. ml에서 int * int-> int는 int와 int의 튜플을 취하고 int에 맵핑하는 함수의 유형입니다.

다른 언어에서 ML에 올 때 인용 한 OLA처럼 모호하게 보이는 오류를 볼 수있는 이유 중 하나는 C 또는 Pascal에서와 같이 괄호와 쉼표를 사용하여 인수를 통과하려고하는 경우 두 개의 매개 변수를 가져옵니다.

문제는 기능적 언어가 일반적으로 함수를 반환하는 함수로서 하나 이상의 매개 변수의 모델 함수를 모델링한다는 것입니다. 모든 기능은 단일 인수 만 가져옵니다. 함수가 두 가지 인수를 취해야한다면 대신 인수를 취하고 단일 인수의 함수를 반환하여 최종 결과를 반환합니다. 이 모든 것을 읽기 쉽게 만들기 위해 기능 응용 프로그램은 단순히 결합하여 수행됩니다 (즉, 표현식을 서로 옆에 배치).

따라서 ML의 간단한 기능 (참고 : ML로 F#을 사용하고 있음)은 다음과 같습니다.

let f x y = x + y;;

유형이 있습니다 :

val f : int -> int -> int

(정수를 가져 와서 그 자체가 정수를 취하고 정수를 반환하는 함수를 반환합니다.)

그러나 순진하게 튜플로 전화하면 :

f(1, 2)

... 당신은 int를 기대하는 무언가에 int*int를 통과했기 때문에 오류가 발생합니다.

나는 이것이 "문제"Ola가 Aspersions를 던지려고했던 "문제"라고 기대한다. 그래도 문제가 생각하는 것만 큼 나쁘다고 생각합니다. 확실히 C ++ 템플릿에서는 훨씬 나쁩니다.

다른 팁

오류 메시지를 명확하게하기 위해 괄호를 삽입하지 못한 잘못 작성된 컴파일러와 관련하여 이것이 가능할 수 있습니다. 구체적으로, 함수는 튜플을 예상했다 int 그리고 반환했다 int, 그러나 당신은 튜플을 통과했습니다 int 그리고 기능 int 에게 int. 더 구체적으로 (ML에서) :

fun f g = g (1, 2);

f (42, fn x => x * 2)

이렇게하면 다음과 유사한 유형 오류가 발생합니다.

예상 유형 int * int -> int, 유형이 있습니다 int * (int -> int)

괄호가 생략되면이 오류는 성가신 모호 할 수 있습니다.

이 문제는 Hindley-Milner와는 거리가 멀다는 점은 주목할 가치가 있습니다. 사실, 나는 이상한 유형을 생각할 수 없습니다. 오류 HM에 특화되어 있습니다. 적어도, 주어진 예제를 좋아하지 않습니다. 나는 Ola가 단지 연기를 불고 있다고 생각합니다.

많은 기능적 언어는 변수를 반환 할 수있는 것과 같은 방식으로 유형 이름을 반환 할 수 있으므로 실제로 유형에 대해 약간 일반적인 이름을 사용하는 경우 이와 같은 오류로 끝나는 것이 실제로 쉽습니다. t) 다른 모듈에서. 다음은 OCAML의 간단한 예입니다.

# let f x = x + 1;;
val f : int -> int = <fun>
# type int = Foo of string;;
type int = Foo of string
# f (Foo "hello");;
This expression has type int but is here used with type int

내가 여기서 한 것은 유형 식별자를 Rebind입니다 int 내장과 호환되지 않는 새로운 유형으로 int 유형. 조금 더 노력하면 위와 같은 오류를 더 많이 얻을 수 있습니다.

# let f g x y = g(x,y) + x + y;;
val f : (int * int -> int) -> int -> int -> int = <fun>
# type int = Foo of int;;
type int = Foo of int
# let h (Foo a, Foo b) = (Foo a);;
val h : int * int -> int = <fun>
# f h;;
This expression has type int * int -> int but is here used with type
  int * int -> int
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top