Список <int> vs int list

Есть ли разница между List<int> и int list? Например, когда я пишу функцию

let somefn a : int list = a

и

let somefn2 a : List<int> = a

Типы возвращаемых значений отличаются стилем нотации и даже на выходе консоли, когда я вызываю эти функции, он показывает два четко обозначенных типа

val it : int list = ...

и

val it : List<int> = ...

Хотя логика и идея кажутся одинаковыми, Interpreter/compiler интерпретирует эти два типа по-другому.

Есть ли разница?

Ответ 1

Чтобы немного раскрыть правильный ответ Джона Палмера, здесь F # Интерактивный сеанс, который иллюстрирует, как int list и List<int> являются синонимами, вплоть до момента, когда они не являются. И обратите внимание, как там также List<int> и ResizeArray<int> для дополнительной путаницы:

F# Interactive for F# 4.0 (Open Source Edition)
Freely distributed under the Apache 2.0 Open Source License

For help type #help;;

> typeof<list<int>>.Namespace ;;
val it : string = "Microsoft.FSharp.Collections"
> typeof<list<int>>.Name ;;     
val it : string = "FSharpList`1"
> typeof<List<int>>.Namespace ;;
val it : string = "Microsoft.FSharp.Collections"
> typeof<List<int>>.Name ;;     
val it : string = "FSharpList`1"
> typeof<int list>.Namespace ;;
val it : string = "Microsoft.FSharp.Collections"
> typeof<int list>.Name ;;     
val it : string = "FSharpList`1"
> typeof<ResizeArray<int>>.Namespace ;;
val it : string = "System.Collections.Generic"
> typeof<ResizeArray<int>>.Name ;;     
val it : string = "List`1"
- 
- printfn "Now we'll open System.Collections.Generic. Watch what happens."
- ;;
Now we'll open System.Collections.Generic. Watch what happens.
val it : unit = ()
> open System.Collections.Generic ;;
> typeof<list<int>>.Namespace ;;
val it : string = "Microsoft.FSharp.Collections"
> typeof<list<int>>.Name ;;
val it : string = "FSharpList`1"
> typeof<List<int>>.Namespace ;;
val it : string = "System.Collections.Generic"
> typeof<List<int>>.Name ;;     
val it : string = "List`1"
> typeof<int list>.Namespace ;;
val it : string = "Microsoft.FSharp.Collections"
> typeof<int list>.Name ;;
val it : string = "FSharpList`1"
> typeof<ResizeArray<int>>.Namespace ;;
val it : string = "System.Collections.Generic"
> typeof<ResizeArray<int>>.Name ;;     
val it : string = "List`1"

So List<int> с верхним регистром L будет типом списка F # (неизменный связанный список с указателем головы, который имеет доступ к O (1) и доступ к нему, но O (N) хвост и добавление), если вы не открыли пространство имен System.Collections.Generic. Но если у вас есть, то вдруг List<int> переходит к классу .Net System.Collections.Generic.List<T>, который является изменяемой структурой данных с O (1) поисками в любом месте, аффицирует O (1), но O (N) добавляет. Поэтому действительно важно, какой из них вы используете.

Чтобы быть в безопасности, если вы намереваетесь использовать структуру списка F #, я бы написал ее как int list (мои предпочтения, так как они читаются как английский) или List<int> (которые некоторые предпочитают с тех пор читается как С#). Ни один из них внезапно не приобретет другой смысл при открытии пространства имен .Net; они будут продолжать ссылаться на структуру списка F #. И избегайте использования List<int> для ссылки на списки F #; используйте это, только когда вы открыли пространство имен System.Collections.Generic, и вы намерены получить экземпляр .Net System.Collections.Generic.List<T>. Наконец, обратите внимание, что в F # System.Collections.Generic.List<T> имеет псевдоним типа, не открывая пространство имен System.Collections.Generic. По умолчанию без открытия каких-либо пространств имен вы можете получить доступ к этому типу под именем ResizeArray<T>.

Резюме:

Безопасные имена типов:

  • int list и List<int> (всегда ссылайтесь на тип списка односвязных F #)
  • ResizeArray<int> (всегда относится к типу С# System.Collections.Generic.List<T>)

Небезопасные имена типов, поскольку их значение изменяется в зависимости от того, какое пространство имен вы открыли:

  • List<int> (сначала ссылается на тип списка с односвязным именем F #, но при изменении пространства имен System.Collections.Generic изменяется значение типа С#). Как правило, не используйте это имя типа; если вы хотите этот тип в F #, используйте ResizeArray<int> вместо этого.

Ответ 2

Нет разницы, существует псевдоним типа.

За исключением одного случая, когда вы запустили

 open System.Collections.Generic

У кого есть собственный тип списка

Ответ 3

  • Как правило, для общих типов с одним параметром TypeParameter GenericType эквивалентно GenericType<TypeParameter>.

  • Тип неизменяемого списка F #, объявленный в FSharp.Core, по умолчанию имеет два имени: List и List. Он имеет один параметр типа, поэтому int list, list<int>, int list и list<int> эквивалентны.

  • System.Collections.Generic имеет другой тип List<'T>, который имеет более подходящий псевдоним ResizeArray в F #. Если вы открываете System.Collections.Generic, List ссылается на этот изменяемый тип массива.

Чтобы избежать путаницы, обычно не использовать List с капиталом L для обозначения типа в F #. Вместо этого List с нижним регистром L используется для FP-исходных, неизменяемых, односвязных списков, а ResizeArray используется для ссылки на изменяемую коллекцию OO-стиля. Большинство людей также придерживаются разных стилей int list по сравнению с ResizeArray<int> и избегают других комбинаций.

Что касается информации о типе, IDE и подобные иногда пытаются отображать типы в том виде, в котором они были объявлены, так как часто есть много способов ссылаться на один и тот же тип. Это не означает различия в поведении.