Types

Type List

Implemented as a linked list:

  • 1 list = 1 element (Head) + 1 sub-list (Tail)

  • Construction using :: Cons operator

To avoid infinite recursion, we need an "exit" case: β†’ Empty list named Empty and noted []

πŸ‘‰ Generic and recursive union type:

type List<'T> =
  | ( [] )
  | ( :: ) of head: 'T * tail: List<'T>

☝️ Note: this syntax with cases as operator is only allowed in FSharp.Core.

Type alias

  • List (big L) refers to the Fβ™― type or its companion module.

  • list (small l) is an alias of Fβ™―'s List type, often used with OCaml notation: β†’ let l : string list = ...

⚠️ Warnings:

  • ❗ After open System.Collections.Generic:

    • List is the Cβ™― mutable list, hiding the Fβ™― type!

    • The List Fβ™― companion module remains available β†’ confusion!

  • πŸ’‘ Use the ResizeArray alias to reference the Cβ™― list directly

    • no need for open System.Collections.Generic πŸ‘

Immutability

A List is immutable: β†’ It is not possible to modify an existing list.

Adding an element in the list: = Cheap operation with the Cons operator (::) β†’ Creates a new list with: β€’ Head = given element β€’ Tail = existing list

🏷️ Related concepts:

  • linked list

  • recursive type

Literals

#
Notation
Equivalent
Meaning (*)

0

[]

[]

Empty

1

[1]

1 :: []

Cons (1, Empty)

2

[2; 1]

2 :: 1 :: []

Cons (2, Cons (1, Empty))

3

[3; 2; 1]

3 :: 2 :: 1 :: []

Cons (3, Cons (2, Cons (1, Empty)))

(*) We can verify it with SharpLab.io :

Initialisation

Exercices πŸ•ΉοΈ

1. Implement the rev function β†’ Inverts a list: rev [1; 2; 3] ≑ [3; 2; 1]

2. Implement the map function β†’ Transforms each element: [1; 2; 3] |> map ((+) 1) ≑ [2; 3; 4]

πŸ’‘ Hints β†’ Use empty list [] or Cons head :: tail patterns β†’ Write a recursive function

Solution

We can verify that it's working in FSI console:

πŸ’‘ Bonus: verify the tail recursion with sharplab.io

Type Array

Signature: 'T array (recommended) or 'T[] or 'T []

Main differences compared to the List:

  • Fixed-size

  • Fat square brackets [| |] for literals

  • Mutable ❗

  • Access by index in O(1) πŸ‘

πŸ’‘ Slicing works also with string: "012345"[1..3] ≑ "123"

Alias ResizeArray

Alias for System.Collections.Generic.List<T> BCL type

Advantages πŸ‘

  • No need for open System.Collections.Generic

  • No name conflicts on List

Notes ☝️

  • Do not confuse the alias ResizeArray with the Array Fβ™― type.

  • ResizeArray is in Fβ™― a better name for the BCL generic List<T>

    • Closer semantically and in usage to an array than a list

Type Seq

Definition: Series of elements of the same type

't seq ≑ Seq<'T> ≑ IEnumerable<'T>

Lazy: sequence built gradually as it is iterated β‰  All other collections built entirely from their declaration

Syntax

seq { items | range | comprehension }

Infinite sequence

2 options to write an infinite sequence

  • Use Seq.initInfinite function

  • Write a recursive function to generate the sequence

Option 1

Seq.initInfinite function

  • Signature: (initializer: (index: int) -> 'T) -> seq<'T>

  • Parameter: initializer is used to create the specified index element (>= 0)

Option 2

Recursive function to generate the sequence

Type Set

  • Self-ordering collection of unique elements (without duplicates)

  • Implemented as a binary tree

Informations

β†’ count, minElement, maxElement

Operations

Operation
Operator
Function for 2 sets
Function for N sets

βŠ–

Difference

-

Set.difference

Set.differenceMany

βˆͺ

Union

+

Set.union

Set.unionMany

∩

Intersection

Γ—

Set.intersect

Set.intersectMany

Examples:

Type Map

Associative array { Key β†’ Value } ≃ Cβ™― immutable dictionary

Access/Lookup by key

Dictionaries

dict function

  • Builds an IDictionary<'k, 'v> from a sequence of key/value pairs

  • The interface is error prone: the dictionary is immutable ❗

readOnlyDict function

  • Builds an IReadOnlyDictionary<'k, 'v> from a sequence of key/value pairs

  • The interface is honest: the dictionary is immutable

Recommendation

dict returns an object that does not implement fully IDictionary<'k, 'v> β†’ Violate the Liskov's substitution principle❗

readOnlyDict returns an object that respects IReadOnlyDictionary<'k, 'v>

πŸ‘‰ Prefer readOnlyDict to dict when possible

KeyValue active pattern

Used to deconstruct a KeyValuePair dictionary entry to a (key, value) pair

Lookup performance

πŸ”— High Performance Collections in Fβ™― β€’ Compositional IT (2021)

Dictionary vs Map

readOnlyDict creates high-performance dictionaries β†’ 10x faster than Map for lookups

Dictionary vs Array

~ Rough heuristics

β†’ The Array type is OK for few lookups (< 100) and few elements (< 100) β†’ Use a Dictionary otherwise

Map and Set vs IComparable

Only works if elements (of a Set) or keys (of a Map) are comparable!

Examples:

F# functional type: tuple, record, union

Structs:

Classes implementing IComparable... but not IComparable<'T> 🀷

Last updated

Was this helpful?