Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

List<int> vs int list in F Sharp

Tags:

list

generics

f#

Is there any difference between List<int> and int list? For example, when I write a function

let somefn a : int list = a

and

let somefn2 a : List<int> = a

Returned value types differ with notation style, and even in the console output, when I invoke those functions, it shows two distinctly noted types

val it : int list = ...

and

val it : List<int> = ...

Although, logic and idea seems to be same, Interpreter/compiler interprets those two types in a different way.

Is there any difference?

like image 741
Giorgi Tsiklauri Avatar asked Dec 12 '16 00:12

Giorgi Tsiklauri


2 Answers

To expand slightly on John Palmer's correct answer, here's an F# Interactive session that illustrates how int list and List<int> are synonyms, right up until the moment when they aren't. And note how there's also list<int> and ResizeArray<int> for extra confusion:

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> with an uppercase L will be the F# list type (an immutable linked list with a head pointer, which has O(1) head access and prepending, but O(N) tail access and appending) if you haven't opened the System.Collections.Generic namespace. But if you have, then suddenly List<int> resolves to the .Net System.Collections.Generic.List<T> class, which is a mutable data structure with O(1) lookups anywhere, amortized O(1) appends, but O(N) prepends. So it really matters which one you're using.

To be on the safe side, if you intend to use the F# list structure, I'd write it as either int list (my preference since it reads like English) or list<int> (which some people prefer since it reads like C#). Neither of those will suddenly acquire a different meaning when you open a .Net namespace; they will continue to refer to the F# list structure. And avoid using List<int> to refer to F# lists; only use that when you have opened the System.Collections.Generic namespace and you intend to get a .Net System.Collections.Generic.List<T> instance. Finally, note that in F#, System.Collections.Generic.List<T> has a type alias available without opening the System.Collections.Generic namespace. By default, without needing to open any namespaces, you can access this type under the name ResizeArray<T>.

Summary:

Safe type names:

  • int list and list<int> (always refer to the F# singly-linked list type)
  • ResizeArray<int> (always refers to the C# System.Collections.Generic.List<T> type)

Unsafe type names because their meaning changes depending on what namespace you've opened:

  • List<int> (refers to the F# singly-linked list type at first, but changes meaning to the C# type if you open the System.Collections.Generic namespace). As a general rule, don't use this type name; if you want this type in F#, use ResizeArray<int> instead.
like image 144
rmunn Avatar answered Oct 02 '22 16:10

rmunn


There is no difference, there is a type alias.

Except under one case, where you have run

 open System.Collections.Generic

Which has its own list type

like image 24
John Palmer Avatar answered Oct 02 '22 16:10

John Palmer