Skip to content

Commit fddf841

Browse files
committed
Vectors and OLList
1 parent 7cbec46 commit fddf841

File tree

1 file changed

+81
-1
lines changed

1 file changed

+81
-1
lines changed

fr/lessons/basics/containers.md

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -513,9 +513,89 @@ Un lecteur averti notera qu'en réalité la _map_ n'est pas mise à jour. Le sec
513513

514514
Les _maps_ sont vraiment très adaptées pour persister en mémoire des états qui devront être récupérer à partir d'une clé, d'un type préalablement définit. Ceci est du au bonnes performances de recherche à partir des clés qui caractérisent les _maps_ grâce à la contraite de tri sur leurs clés, on a une complexité asymptotique (`𝛰(log n)`). Un exemple évident est le stockage de session sur un serveur d'une application web. L'état de la session peut être stocké dans une _map_ avec l'id présent dans le _cookie_ de session comme clé. Ainsi, l'état de la session est accessible de manière performante via cette _map_ pour chaque requête. Cette solution ne permet pas non plus de gérer un nombre infini de session mais vous serez étonnés de voir à quelle point elle est efficace, pour répondre simplement aux besoins de la plupart des applications !
515515

516-
### Une _Map_ avec des clés sans contraintes de tri : _HashMaps_
516+
### Une _Map_ avec "des clés sans contraintes de tri" : _HashMaps_
517517

518518
Dans certains cas, on veut utiliser comme clé, un type qui ne respecte pas la contrainte de tri. Les _Hashmap_ sont faites pour ça. Une _Hashmap_ va "hacher" la clé (quelque soit le type tant qu'il est _hashable_) pour la rendre "ordonnable" !
519519

520520
Le module qui exporte le type `HashMap` et ses fonctions est `Data.HashMap.Strict`, il fait parti du _package_ `unordered-containers`. L'_api_ est identique à celle de `Map` excepté que la contrainte sur la clé est `Hashable k` au lieu de `Ord k`.
521521

522+
## Vectors
523+
524+
Parfois on souhaite avoir une _list_ comme _conatiner_ avec de bonnes performances d'accès aux données. Dans la plupart des langages, les _arrays_ sont la structure de données de base pour gérer des séquences de données. Haskell possède également ce type de structure de données et l'implémentation la plus populaire est le type `Vector` de la bibliothèque `vector`.
525+
526+
Un des aspects les plus intéressants à propos de ce type est qu'il offre un accès aux données de `𝛰(1)`. La bibliothèque offre les deux types d'accesseurs _safe_ et _unsafe_ comme pour les _lists_ vues précédemment.
527+
528+
Voici un exemple d'un _container_ qui nous permet de stocker et récupérer les caractères _ascii_ à partir de leur code.
529+
530+
__Note__: Vous pouvez installer la biblithèques `vector` dans votre interpréteur _ghci_ grâce aux commandes : `cabal repl --build-depends "vector"` ou `stack exec --package vector -- ghci`
531+
532+
```haskell
533+
ghci> import Data.Vector as V
534+
ghci> asciiChars = V.fromList ['\NUL'..'\DEL']
535+
ghci> asciiChars ! 48
536+
'0'
537+
ghci> asciiChars ! 97
538+
'a'
539+
ghci> asciiChars ! 65
540+
'A'
541+
ghci> asciiChars !? 65
542+
Just 'A'
543+
ghci> asciiChars !? 128
544+
Nothing
545+
ghci> asciiChars !? 127
546+
Just '\DEL'
547+
```
548+
549+
Ils offrent également une capacité à subdiviser un _vector_ en plusieurs autres de manière performante `𝛰(1)`. la fonction `slice` prend un index de départ, la longueur voulue et le _vector_ à subdiviser, elle retourne le nouveau _vector_. Cette fonction est _unsafe_ : si l'index de départ additionné à la longueur demandée donne un résultat supérieur à la longueur du _vector_ une erreur aura lieu à l'exécution (_runtime error_) !
550+
551+
```haskell
552+
ghci> :t V.slice
553+
V.slice :: Int -> Int -> Vector a -> Vector a
554+
ghci> lowerCase = V.slice 97 26 asciiChars
555+
ghci> lowerCase
556+
"abcdefghijklmnopqrstuvwxyz"
557+
ghci> upperCase = V.slice 65 26 asciiChars
558+
ghci> upperCase
559+
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
560+
ghci> nums = V.slice 48 10 asciiChars
561+
ghci> V.length nums
562+
128
563+
ghci> nums
564+
"0123456789"
565+
-- Error case, the asciiChars vectors has length 128, and our slice supposes a
566+
-- length of 97 + 92 (189)
567+
ghci> V.slice 97 92 asciiChars
568+
"*** Exception: ./Data/Vector/Generic.hs:408 (slice): invalid slice (97,92,128)
569+
CallStack (from HasCallStack):
570+
error, called at ./Data/Vector/Internal/Check.hs:87:5 in vector-0.12.3.0-8cc976946fcdbc43a65d82e2ca0ef40a7bb90b17e6cc65c288a8b694f5ac3127:Data.Vector.Internal.Check
571+
```
572+
573+
## Overloaded Lists
574+
575+
Vous aurez noté que l'on utilise souvent la fonction `fromList` pour construire nos _containers_. Il y a une extension (`OverloadedLists`) qui permet d'utiliser la syntaxe de création des _lists_. L'inconvénient est que si le type n'est pas explicitement fournit les messages d'erreur ne seront pas précis.
576+
577+
```haskell
578+
ghci> :set -XOverloadedLists -- This is the language extension
579+
ghci> [1,2,3] :: Set Int
580+
fromList [1,2,3]
581+
ghci> [1,2,3] :: Vector Int
582+
[1,2,3]
583+
ghci> [('a', 1),('b', 2),('c', 3)] :: Map Char Int
584+
fromList [('a',1),('b',2),('c',3)]
585+
```
586+
587+
Si on n'explicite pas le type voulu...
588+
589+
```haskell
590+
ghci> ["1", "2", "3"]
591+
592+
<interactive>:11:1: error:
593+
• Illegal equational constraint GHC.Exts.Item l ~ [Char]
594+
(Use GADTs or TypeFamilies to permit this)
595+
• When checking the inferred type
596+
it :: forall {l}.
597+
(GHC.Exts.IsList l, GHC.Exts.Item l ~ [Char]) =>
598+
l
599+
```
600+
601+
L'erreur est particulièrement peut explicite, c'est pourquoi cette extension n'est pas activée par défaut. C'est toujours bon à savoir !

0 commit comments

Comments
 (0)