Types

Type List

Implémentée sous forme de liste simplement chaînée : → 1 liste = 1 élément (Head) + 1 sous-liste (Tail) → Construction nommée Cons et notée ::

Pour éviter récursion infinie, besoin d'un cas de "sortie" : → Liste vide nommée Empty et notée []

👉 Type union générique et récursif :

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

Alias de types

  • Par défaut, List fait référence au type (ou au module) F#

  • list est un alias du type List de F#, utilisé souvent avec la notation OCaml : → let l : string list = ...

  • Si on fait un open System.Collections.Generic, List fera référence à la liste mutable C# et masquera le type List F# mais sera fusionné avec le module List F# !

  • Pour éviter cela, on peut utiliser l'alias ResizeArray pour référencer la liste mutable C# directement, sans devoir faire open System.Collections.Generic.

Littéraux

Nb
Notation
Notation explicite
Signification

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)))

Vérification par décompilation avec SharpLab.io :

Immuable

Il n'est pas possible de modifier une liste existante. → C'est cela qui permet de l'implémenter en liste chaînée.

💡 L'idée est de créer une nouvelle liste pour signifier un changement. → Utiliser les opérateurs Cons (::) et Append (@) 📍

Initialisation

Exercices 🕹️

1. Implémenter la fonction rev

Inverse une liste : rev [1; 2; 3][3; 2; 1]

2. Implémenter la fonction map

Transforme chaque élément : [1; 2; 3] |> map ((+) 1)[2; 3; 4]

💡 Astuces → Pattern matching liste vide [] ou Cons head :: tail → Sous-fonction (tail-) recursive

Solution 🎲

💡 Vérification avec sharplab.io de la tail recursion compilée en boucle while

Vérification en console FSI ✅

Type Array

  • Différences / List : mutable, taille fixe, accès indexé en O(1)

  • Signature générique : 'T array (récemment recommandée) ou 'T []

  • Littéral et comprehension : similaires à List

Accès indexé & mutation

Accès par index : my-array.[my-index]

⚠️ Piège : ne pas oublier le . avant les crochets [] ❗ 🎁 F♯ 6.0 supporte sans le . : my-array[my-index]

Slicing

Renvoie un sous-tableau entre les indices start..end optionnels

💡 Marche aussi avec une string : "012345".[1..3]"123"

Alias ResizeArray

☝️ Ne pas confondre le type List<T> de F♯ avec celui de .NET dans le namespace System.Collections.Generic.

Même si les listes .NET ne sont pas très souvent utilisées en F♯, quand on en a besoin (par exemple en interop), il vaut mieux utiliser l'alias ResizeArray qui permet d'éviter la confusion avec les listes F♯.

☝️ Ne pas confondre l'alias ResizeArray avec le type Array de F♯.

Type Seq

type Seq<'T> = IEnumerable<'T> → Série d'éléments de même type

Lazy : séquence construite au fur et à mesure lors de son itération ≠ List construite dès la déclaration

→ Peut offrir de meilleures performances qu'un List pour une collection avec beaucoup d'éléments et qu'on ne souhaite pas parcourir entièrement.

Syntaxe

seq { comprehension }

Séquence infinie

Option 1 : appeler la fonction Seq.initInfinite : → Seq.initInfinite : (initializer: (index: int) -> 'T) -> seq<'T> → Paramètre initializer sert à créer l'élément d'index (>= 0) spécifié

Option 2 : écrire une fonction récursive générant la séquence

Type Set

Collection auto-ordonnée d'éléments uniques (sans doublon) → Implémentée sous forme d'arbre binaire

Informations

count, minElement, maxElement

Opérations

Union, Différence, Intersection (idem ensembles en Math)

Opération
?
Opérateur
Fonction 2 sets
Fonction N sets

Union

+

Set.union

Set.unionMany

Différence

-

Set.difference

Set.differenceMany

Intersection

Set.intersect

Set.intersectMany

Exemples :

Valeur
Union
Différence
Intersection

A

[ 1 2 3 4 5 ]

[ 1 2 3 4 5 ]

[ 1 2 3 4 5 ]

B

[ 2 4 6 ]

[ 2 4 6 ]

[ 2 4 6 ]

Résultat

A + B [ 1 2 3 4 5 6 ]

A - B [ 1 3 5 ]

A ∩ B [ 2 4 ]

Type Map

Tableau associatif { CléValeur } ≃ Dictionary immutable en C♯

Accès par clé

Dictionnaires

dict function

Construit un IDictionary<'k, 'v> immutable ❕ à partir d'une séquence de pairs clé/valeur

readOnlyDict function

Construit un IReadOnlyDictionary<'k, 'v> à partir d'une séquence de pairs clé/valeur

👉 Recommendation Préférer readOnlyDict à dict car l'interface IReadOnlyDictionary<'k, 'v> est + fidèle à l'implémentation sous-jacente. Au contraire, dict ne respecte pas le principe de substitution de Liskov !

KeyValue active pattern

  • Permet de déconstruire une entrée KeyValuePair d'un dictionnaire en passant par un tuple (clé, valeur)

  • Signature:

Performance des lookups (find)

🔗 High Performance Collections in F#, Compositional IT, Jan 2021

Map vs Dictionary

Fonction readOnlyDict permet de créer rapidement un IReadOnlyDictionary → à partir d'une séquence de tuples key, item → très performant : 10x plus rapide que Map pour le lookup

Dictionary vs Array

Array suffit si peu de lookups (< 100) et peu d'éléments (< 100) → Dictionary sinon

Set et Map vs IComparable

Ne marchent que si les éléments (d'un Set) ou les clés (d'une Map) sont comparables !

🎉 Compatibles avec tous les types F♯ (cf. égalité et comparaison structurelles)

⚠️ Pour les classes : implémenter IComparable (mais pas IComparable<'T>)

Last updated

Was this helpful?