dodgy_coder
dodgy_coder

Reputation: 13063

When to use a sequence in F# as opposed to a list?

I understand that a list actually contains values, and a sequence is an alias for IEnumerable<T>. In practical F# development, when should I be using a sequence as opposed to a list?

Here's some reasons I can see when a sequence would be better:

Are there any others?

Upvotes: 94

Views: 15236

Answers (5)

Rm558
Rm558

Reputation: 5002

list is more functional, math-friendly. when each element is equal, 2 lists are equal.

sequence is not.

let list1 =  [1..3]
let list2 =  [1..3]
printfn "equal lists? %b" (list1=list2)

let seq1 = seq {1..3}
let seq2 = seq {1..3}
printfn "equal seqs? %b" (seq1=seq2)

enter image description here

Upvotes: 8

Aleš Roub&#237;ček
Aleš Roub&#237;ček

Reputation: 5187

You should always expose Seq in your public APIs. Use List and Array in your internal implementations.

Upvotes: 6

J D
J D

Reputation: 48717

Also prefer seq when:

  • You don't want to hold all elements in memory at the same time.

  • Performance is not important.

  • You need to do something before and after enumeration, e.g. connect to a database and close connection.

  • You are not concatenating (repeated Seq.append will stack overflow).

Prefer list when:

  • There are few elements.

  • You'll be prepending and decapitating a lot.

Neither seq nor list are good for parallelism but that does not necessarily mean they are bad either. For example, you could use either to represent a small bunch of separate work items to be done in parallel.

Upvotes: 32

Tomas Petricek
Tomas Petricek

Reputation: 243096

I think your summary for when to choose Seq is pretty good. Here are some additional points:

  • Use Seq by default when writing functions, because then they work with any .NET collection
  • Use Seq if you need advanced functions like Seq.windowed or Seq.pairwise

I think choosing Seq by default is the best option, so when would I choose different type?

  • Use List when you need recursive processing using the head::tail patterns
    (to implement some functionality that's not available in standard library)

  • Use List when you need a simple immutable data structure that you can build step-by-step
    (for example, if you need to process the list on one thread - to show some statistics - and concurrently continue building the list on another thread as you receive more values i.e. from a network service)

  • Use List when you work with short lists - list is the best data structure to use if the value often represents an empty list, because it is very efficient in that scenario

  • Use Array when you need large collections of value types
    (arrays store data in a flat memory block, so they are more memory efficient in this case)

  • Use Array when you need random access or more performance (and cache locality)

Upvotes: 111

pad
pad

Reputation: 41290

Just one small point: Seq and Array are better than List for parallelism.

You have several options: PSeq from F# PowerPack, Array.Parallel module and Async.Parallel (asynchronous computation). List is awful for parallel execution due to its sequential nature (head::tail composition).

Upvotes: 13

Related Questions