В вашем случае B.empty
у вас есть значение для привязки, где вы вводите параметры типа 'k
и 'v
с правой стороны, не обращаясь к ним с левой стороны.В этом случае механизм вывода типов не может автоматически обобщить empty
и вместо этого назначает ему определенный тип.
Если вы попытаетесь использовать его в разных экземплярах, вы увидите, что второй отказал:
let t1 : B<int, string> = B.empty
let t2 : B<string, int> = B.empty // <- getting a type mismatch here.
Это связано со свойством механизма вывода типов, называемого ограничением значения. В этом посте есть хорошее подробное описание, включая тот самый случай, который вы сейчас рассматриваете, реализацию empty
для универсального типа контейнера.
Короче -B.empty
не может быть обобщено здесь, потому что выражение справа не дает значения, которое легко идентифицировать как неизменяемое, и поэтому компилятор ошибается и решает не обобщать тип empty
.
С другой стороны, A.empty
справа содержит выражение, создающее экземпляр неизменяемой записи, что является одним из редких сценариев, отвечающих требованиям для автоматического обобщения.
Некоторые способы избежать этого:
Создание empty
функции:
let empty () = new B<'k, 'v>(Map.empty)
Установка явных аргументов типана нем:
let empty<'k, 'v when 'v : comparison and 'k : comparison> = new B<'k, 'v>(Map.empty)