Types
Type List
ListImplemented 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♯'sListtype, often used with OCaml notation: →let l : string list = ...
⚠️ Warnings:
❗ After
open System.Collections.Generic:Listis the C♯ mutable list, hiding the F♯ type!The
ListF♯ companion module remains available → confusion!
💡 Use the
ResizeArrayalias to reference the C♯ list directlyno 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
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
We can verify that it's working in FSI console:
💡 Bonus: verify the tail recursion with sharplab.io
Type Array
ArraySignature: 'T array (recommended) or 'T[] or 'T []
Main differences compared to the List:
Fixed-size
Fat square brackets
[| |]for literalsMutable ❗
Access by index in
O(1)👍
💡 Slicing works also with string: "012345"[1..3] ≡ "123"
Alias ResizeArray
ResizeArrayAlias for System.Collections.Generic.List<T> BCL type
Advantages 👍
No need for
open System.Collections.GenericNo name conflicts on
List
Notes ☝️
Do not confuse the alias
ResizeArraywith theArrayF♯ type.ResizeArrayis in F♯ a better name for the BCL genericList<T>Closer semantically and in usage to an array than a list
Type Seq
SeqDefinition: 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.initInfinitefunctionWrite a recursive function to generate the sequence
Option 1
Seq.initInfinite function
Signature:
(initializer: (index: int) -> 'T) -> seq<'T>Parameter:
initializeris used to create the specified index element (>= 0)
Option 2
Recursive function to generate the sequence
Type Set
SetSelf-ordering collection of unique elements (without duplicates)
Implemented as a binary tree
Informations
→ count, minElement, maxElement
Operations
⊖
Difference
-
Set.difference
Set.differenceMany
∪
Union
+
Set.union
Set.unionMany
∩
Intersection
×
Set.intersect
Set.intersectMany
Examples:
Type Map
MapAssociative array { Key → Value } ≃ C♯ immutable dictionary
Access/Lookup by key
Dictionaries
dict function
dict functionBuilds an
IDictionary<'k, 'v>from a sequence of key/value pairsThe interface is error prone: the dictionary is immutable ❗
readOnlyDict function
readOnlyDict functionBuilds an
IReadOnlyDictionary<'k, 'v>from a sequence of key/value pairsThe 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
KeyValue active patternUsed to deconstruct a KeyValuePair dictionary entry to a (key, value) pair
Lookup performance
🔗 High Performance Collections in F♯ • Compositional IT (2021)
Dictionary vs Map
Dictionary vs MapreadOnlyDict creates high-performance dictionaries
→ 10x faster than Map for lookups
Dictionary vs Array
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
Map and Set vs IComparableOnly 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