Почему предполагаемые типы F # в этих двух определениях различаются в отношении IComparable и сравнения? - PullRequest
0 голосов
/ 06 октября 2018

Работая в 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 Ответ

0 голосов
/ 06 октября 2018

В вашем случае 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)
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...