Понимание ошибки типа:«ожидалась подпись Int*Int->Int, но получена Int*Int->Int»

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

  •  11-07-2019
  •  | 
  •  

Вопрос

Комментарии к Стив Йегге's почта о серверный Javascript начал обсуждать достоинства систем типов в языках, и это комментарий описывает:

...примеры из ЧМ системы стилей, где вы можете получить такие вещи, как:

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

Можете ли вы привести пример определения функции (или двух?) и вызова функции, который приведет к этой ошибке?Похоже, что отладку в большой программе может быть довольно сложно.

Кроме того, возможно, я видел подобную ошибку в Миранда?(Я не пользовался им уже 15 лет, поэтому мои воспоминания о нем смутны)

Это было полезно?

Решение

Я бы взял мнение Йегге (и Олы Бини) о статической типизации с частичкой соли. Если вы понимаете, что дает статическая типизация, вы узнаете, как работает система типов выбранного вами языка программирования.

IIRC, ML использует синтаксис '*' для кортежей. & Lt; тип & GT; * < тип > тип кортежа с двумя элементами Таким образом, (1, 2) будет иметь тип int * int.

И Хаскель, и МЛ используют - > для функций. В ML int * int - > int будет типом функции, который принимает кортеж int и int и отображает его в int.

Одна из причин, по которой вы можете увидеть ошибку, которая выглядит смутно как та, которую Ола цитирует при переходе на ML с другого языка, заключается в том, что если вы пытаетесь передать аргументы, используя скобки и запятые, как в C или Pascal, функция, которая принимает два параметра.

Проблема в том, что функциональные языки обычно моделируют функции нескольких параметров как функции, возвращающие функции; все функции принимают только один аргумент. Если функция должна принимать два аргумента, она вместо этого принимает аргумент и возвращает функцию с одним аргументом, которая возвращает конечный результат, и так далее. Чтобы сделать все это разборчивым, применение функции выполняется простым соединением (то есть размещением выражений рядом друг с другом).

Итак, простая функция в ML (обратите внимание: я использую F # в качестве ML) может выглядеть примерно так:

let f x y = x + y;;

имеет тип:

val f : int -> int -> int

(Функция, принимающая целое число и возвращающая функцию, которая сама принимает целое число и возвращает целое число.)

Однако, если вы наивно называете его с помощью кортежа:

f(1, 2)

... вы получите ошибку, потому что вы передали int * int чему-то, ожидающему int.

Я ожидаю, что это "проблема" Ола пытался бросить оскорбления в. Я не думаю, что проблема настолько плоха, как он думает; конечно, это намного хуже в шаблонах C ++.

Другие советы

Возможно, это было связано с плохо написанным компилятором, которому не удалось вставить скобки для устранения неоднозначности сообщений об ошибках. В частности, функция ожидала кортеж int и вернула int , но вы передали кортеж int и функцию из int в int . Более конкретно (в ОД):

fun f g = g (1, 2);

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

Это приведет к ошибке типа, подобной следующей:

  

Ожидаемый тип int * int - > int , получил тип int * (int - > int)

Если круглые скобки опущены, эта ошибка может быть досадно неоднозначной.

Стоит отметить, что эта проблема далеко не специфична для Хиндли-Милнера. На самом деле, я не могу думать ни о каких странных типах ошибок , характерных для H-M. По крайней мере, ни один из приведенных примеров. Я подозреваю, что Ола просто курил.

Поскольку многие функциональные языки позволяют перепривязывать имена типов так же, как перепривязку переменных, на самом деле довольно легко получить подобную ошибку, особенно если вы используете несколько общие имена для своих типов (например, 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

Здесь я перепривязал идентификатор типа. 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