Работаете на F # и не можете понять разницу в следующих двух элементах:
type A<'k, 'v when 'v : comparison and 'k : comparison> =
{ Keys: Map<'v, 'k> } with
member this.length = Map.count this.Keys
module A =
let empty = { Keys = Map.empty }
type B<'k, 'v when 'v : comparison and 'k : comparison>(keys: Map<'v, 'k>) =
member __.length = Map.count keys
module B =
let empty = new B<'k, 'v>(Map.empty)
Если я посмотрю на предполагаемые типы A.empty и B.empty, я получу следующее:
val empty : A<'a,'b> (requires comparison and comparison)
val empty : B<System.IComparable,System.IComparable>
Почему они разные? И k, и v назначаются карте F # и используются одинаково. Единственное отличие - это ключевое слово «новое» на B, но почему это изменит типы, выведенные для карты?
1 ответ
В случае B.empty
у вас есть значение с привязкой к let, где вы вводите параметры типа 'k
и 'v
с правой стороны, не обращаясь к ним с левой стороны. Механизм вывода типа тогда не может автоматически обобщить empty
и вместо этого присваивает ему определенный тип.
Если вы попытаетесь использовать его в разных экземплярах, вы увидите, что второй не работает:
let t1 : B<int, string> = B.empty
let t2 : B<string, int> = B.empty // <- getting a type mismatch here.
Это происходит из-за свойства механизма вывода типов, называемого ограничением значений. Это сообщение в блоге У a> есть хорошее подробное описание этого, включая тот самый случай, который вы сейчас рассматриваете, реализация 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)
Похожие вопросы
Новые вопросы
f#
F # - это сжатый, выразительный и эффективный функциональный и объектно-ориентированный язык для .NET, который помогает вам писать простой код для решения сложных задач.