diff --git a/book/src/part08.md b/book/src/part08.md
index 823eefb6a22ea90f08c1de99c6ed85a77a31b79d..5785b79c9b230aff7dd76b542c9b4a7942b48fa6 100644
--- a/book/src/part08.md
+++ b/book/src/part08.md
@@ -1 +1,232 @@
-# Part 08
+# Discussion du code `part08`
+
+## Concepts
+
+Les concepts abordés dans cet exemple sont:
+
+- [Discussion du code `part08`](#discussion-du-code-part08)
+  - [Concepts](#concepts)
+  - [Documentation](#documentation)
+  - [Discussion](#discussion)
+    - [Fonctions anonymes](#fonctions-anonymes)
+    - [Fonction d'ordre supérieur](#fonction-dordre-supérieur)
+    - [Closures](#closures)
+    - [Exemples d'utilisation avec les options](#exemples-dutilisation-avec-les-options)
+
+## Documentation
+
+Afin de compléter ce cours, je vous recommande la lecture des ressources suivantes :
+
+- [Les fonctions anonymes closures en Rust](https://doc.rust-lang.org/book/ch13-01-closures.html)
+- [La transformation d'une option avec des closures](https://doc.rust-lang.org/std/option/#transforming-contained-values)
+- [Les fonctions d'ordre supérieur et les closures](https://doc.rust-lang.org/book/ch19-05-advanced-functions-and-closures.html)
+
+## Discussion
+
+De plus en plus de langages proposent des fonctions anonymes (des fonctions sans identifiant). Ces fonctions sont un outil précieux de la
+programmation fonctionelle qui gagne elle aussi en popularité. Nous présenterons dans ce cours ce qu'elles sont
+et les avantages qu'elles peuvent apporter.
+
+
+### Fonctions anonymes
+
+Une fonction anonyme est une fonction sans identifiant, qui permet de transformer un comportement en variable.
+
+Prenons un exemple simple :
+
+```rust,ignore
+|x: i32| -> i32 { x + 1 }
+```
+
+Nous avons entre `|` les arguments de notre fonction anonyme, ici `x` qui est de type `i32`. À la suite
+du deuxième `|`, nous avons le type de retour et finalement entre `{}`, une expression qui est le corps
+de la fonction. Il n'est pas obligatoire d'indiquer le type de l'argument, le type de retour ou de mettre
+entre accolades le corps de la fonction, cela dépendra des déductions que le compilateur peut réaliser. 
+En une phrase, on peut lire l'expression ci-dessus comme étant : "Une fonction qui pour tout entier
+signé de 32 bits x donne x + 1".
+
+Cette expression en Rust est une fonction anonyme. Son équivalent en fonction standard serait :
+
+```rust,ignore
+fn add_one(x:i32) -> i32 {
+  x + 1 
+}
+```
+
+Il est possible de stocker nos fonctions anonymes dans une variable, par exemple :
+
+```rust,ignore
+{{#include ../../codes/rust_lang/part08/src/main.rs:max_variable}}
+```
+
+### Fonction d'ordre supérieur
+
+Une fonction d'ordre supérieur est une fonction qui prends en argument une ou plusieurs fonctions
+et/ou retourne une ou plusieurs fonctions.
+
+L'intérêt principal de nos fonctions anonyme est de pouvoir les passer et les retourner via des
+fonctions.
+
+Prenons un petit exemple :
+
+```rust
+fn plus_two(x: i32, add_one: fn (i32) -> i32) -> i32 {
+  add_one(add_one(x))
+}
+
+fn main(){
+  let add_one = |x| x + 1;
+  println!("{}", plus_two(5, add_one));
+}
+```
+
+Ici nous avons une fonction qui additionne 2 à un entier `x`, mais pour cela notre fonction doit tout d'abord
+savoir additionner 1. Elle prend donc en argument l'entier `x` auquel elle doit additionner 2, et une fonction
+permettant d'additioner 1 à un nombre appelée add_one.
+
+Si on se penche sur cet argument nous avons `add_one: fn (i32) -> i32`, le type de cet argument est une fonction,
+qui prends un `i32` et retourne un `i32`.
+
+Puisque la fonction `plus_two` prends en argument une fonction, il s'agit d'une fonction d'ordre supérieur.
+
+Dans la fonction `main`, on déclare une variable `add_one` qui va contenir une fonction anonyme qui additione 1
+à un entier. A titre d'illustration nous appliquons `plus_two` à 5 et notre fonction anonyme stockée
+dans une variable nommée `add_one`.
+
+Cet exemple est un peu trivial, mais il permet de saisir brièvement la syntaxe.
+
+Nous pouvons modifier notre exemple du calcul du minimum d'une liste, pour y ajouter des fonctions d'ordre supérieur.
+Dans un premier temps, nous pouvons généraliser le comportement de notre fonction de recherche du minimum. Pour cela,
+On commence par créer un type `BinaryOperator<T>` :
+
+```rust,ignore
+{{#include ../../codes/rust_lang/part08/src/binary_operator.rs:binary_operator}}
+```
+
+Si on lit sa définition, on s'apperçoit qu'il s'agit d'une fonction qui prends deux éléments de type `T` et en retourne
+un troisième du même. Cette définition s'applique parfaitement à la fonction minimum, je prends deux éléments du même type, 
+je détermine lequel est le plus petit et je le retourne.
+
+Prenons maintenant le code de notre fonction du calcul du minimum généralisée :
+
+```rust,ignore
+{{#include ../../codes/rust_lang/part08/src/find.rs:find_with_hof}}
+```
+
+Cette fonction est sensiblement la même que la fonction étudiée dans par la [partie 07](./part07.md). Le premier
+changement qu'il faut remarquer, intervient au niveau des arguments.
+
+On voit apparaître un nouvel argument `op: BinaryOperator<T>`. Il s'agit simplement de l'opération que
+nous allons utiliser itérativement sur notre tableau, afin d'obtenir un résultat. On pourrait prendre par
+exemple la fonction minimum.
+
+Contrairement au trait `Minimum` que nous avions défini jusqu'à maintenant, nous allons gérer manuellement
+le résultat qui est intialisé à `None`.  La deuxième modification que nous devons remarquer se trouve dans
+le corps de la boucle. Pour gérer le résultat vide que l'on recontre durant la première itération, 
+on utilise un simple assignation conditionnelle comme nous l'avons vu dans les cours précédent.
+
+Avec cette fonction d'ordre supérieur, nous pouvons désormais utiliser n'importe quelle opération qui réduit deux éléments en un seul.
+
+En utilisant un autre type de fonction d'ordre supérieur, celles qui retournent un fonction, on peut
+générer plusieurs opérateurs de ce type.
+
+```rust,ignore
+{{#include ../../codes/rust_lang/part08/src/binary_operator.rs:minimum_operator}}
+{{#include ../../codes/rust_lang/part08/src/binary_operator.rs:maximum_operator}}
+{{#include ../../codes/rust_lang/part08/src/binary_operator.rs:sum_operator}}
+{{#include ../../codes/rust_lang/part08/src/binary_operator.rs:mul_operator}}
+```
+
+Pour l'utiliser ces fonctions rien de plus simple :
+
+```rust,ignore
+{{#include ../../codes/rust_lang/part08/src/main.rs:min_usage}}
+```
+
+Il suffit d'appeler la fonction `minimum_operator` qui va nous retourner notre fonction anonyme capable de
+déterminer le minimum entre entre deux nombres.
+
+On voit ici tout l'intérêt de nos fonctions d'ordre supérieur. Il me suffit d'écrire une seul fois le code
+qui réduit mon tableau et je peux choisir mon opération en lui passant simplement le comportement en argument,
+comme si c'était une variable quelconque.
+
+### Closures
+
+En Rust, les fonctions anonymes se nomment closures. On recontre parfois la traduction fermetures. Les closures
+ne sont pas simplement des fonctions sans identifiant, en effet, une closure **capture** son environement.
+Une closure est composée d'une fonction anonyme et des variables capturée dans son environnement.
+
+Voici un exemple de code qui illustre le concept de caputre :
+
+```rust
+fn main(){
+  let a : i32 = 50;
+  let divide_by_a = |x:i32| x / a;
+  println!("{}", divide_by_a(100));
+}
+```
+
+Ici nous avons une variable `a` qui contient un `i32` et une variable `divide_by_a` qui contient une closure qui
+prend un `i32` en argument et retourne un `i32`. Ce qu'il faut remarquer, c'est que la variable `a` est **capturée**
+par la closure. Ce qui siginifie que si je passais la variable `divide_by_a` à une fonction, la variable `a` serait
+elle aussi passée indirectement.
+
+Jusqu'à maintenant, nous nous sommes contentés de passer en argument des closures qui ne capturaient aucune variable.
+Pour passer par exemple notre closure `divide_by_a` qui capture une variable, il nous faudra utiliser par exemple le trait
+[`Fn`](https://doc.rust-lang.org/std/ops/trait.Fn.html). Sans entrer dans les détails, c'est l'un des trois traits
+qu'implémentent toutes les closures. Nous ne verrons pas les deux autres dans le cadre de ce cours, mais nous avons 
+[`FnOnce`](https://doc.rust-lang.org/std/ops/trait.FnOnce.html) et [`FnMut`](https://doc.rust-lang.org/std/ops/trait.FnMut.html)
+
+Modifions donc notre code pour ajouter une fonction :
+
+```rust
+fn do_stuff<F: Fn(i32) -> i32>(op: F) -> i32 {
+  op(100)
+}
+fn main(){
+  let a: i32 = 50;
+  let divide_by_a = |x: i32| x / a;
+  println!("{}", do_stuff(divide_by_a));
+}
+```
+
+Dans le code ci-desssus, on peut voir que la fonction `do_stuff` prends un argument appelé `op` de type générique `F`.
+Notre type générique `F` est un type implémentant `Fn(i32) -> i32`, c'est à dire une fonction qui prend
+en argument un `i32` et retourne un `i32`. Il ne faut surtout pas confondre `fn` qui est un mot clé du langage et `Fn`,
+qui est un trait décrivant entre autre une closure qui capture des éléments de son environnement.
+
+### Exemples d'utilisation avec les options
+
+Les options proposent également des méthodes qui prennent en argument d'autres fonctions. Nous pouvons en voir deux
+dans notre code.
+
+- map
+- filter
+
+La fonction map permet de transformer le contenu d'une option si celle-ci n'est pas None, ou de ne rien faire
+dans le cas contraire. Prenons l'exemple suivant :
+
+```rust,ignore
+{{#include ../../codes/rust_lang/part08/src/main.rs:option_map}}
+```
+Dans le code ci-dessus, nous pouvons voir un exemple d'utilisation de la méthode map. Nous récupérons tout d'abord
+la somme des éléments du tableau, sous forme d'option. Ensuite, pour transformer cette option, on utilise une closure,
+qui permet de diviser un `i32` par deux et qui retourne un `f32`. On transforme donc une `Option<i32>` en `Option<f32>`.
+Si la méthode `find_with_hof` retourne une option vide, alors l'option retournée par map reste `None`.
+
+```rust,ignore
+{{#include ../../codes/rust_lang/part08/src/main.rs:option_filter}}
+```
+
+Ici, nous pouvons voir un exemple d'utilisation de la méthode filter. Nous cherchons le plus grand élément du tableau.
+Ensuite, nous essayons de déterminer sa parité à l'aide d'une closure qui retourne `true` si le nombre est impaire.
+
+Ici, nous avons 2 étapes :
+
+- La fonction `find_with_hof` retourne une option `max_val`
+- Sur `max_val`, nous appliquons un filtre, ce qui nous donne `odd_max`. Nous avons donc 3 cas possibles
+  - Si `odd_max` contient une valeur et que cette valeur est impaire, on affiche
+    un message qui annonce que le maximum est impaire.
+  - Sinon si l'`max_val` contient une valeur, on affiche
+    un message qui annonce que le maximum est paire.
+  - Sinon, `max_val` est `None` et donc il n'y a pas de maximum.
diff --git a/codes/rust_lang/part08/src/big_int.rs b/codes/rust_lang/part08/src/big_int.rs
deleted file mode 100644
index d52815b485df22c780b8d2363d7b32da3384521f..0000000000000000000000000000000000000000
--- a/codes/rust_lang/part08/src/big_int.rs
+++ /dev/null
@@ -1,117 +0,0 @@
-use crate::minimum::Minimum;
-
-/// Larger ints based on a [Vec] of [u8] to repensent arbitrary lengthy numbers.
-/// The number has a sign as well.
-pub struct BigInt {
-    /// The data contains the unsigned integers that are read from right to left
-    /// The number 1337 is stored as vec![7, 3, 3, 1]. Each number must be in the range [0,9]
-    /// and no trailing 0s are allowed.
-    data: Vec<u8>,
-    /// Contains the sign of the number +/-1;
-    sign: i8,
-}
-
-impl BigInt {
-    /// Tries to create a new [BigInt]. If the number is valid it returns
-    /// an Ok(BigInt) an Error otherwise.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use part08::big_int::BigInt;
-    /// let num = BigInt::try_new(vec![1, 2, 3, 4], 1);
-    /// assert!(num.is_ok());
-    /// let num = BigInt::try_new(vec![1, 2, 3, 4], -1);
-    /// assert!(num.is_ok());
-    /// let num = BigInt::try_new(vec![1, 2, 3, 4], 10);
-    /// assert!(num.is_err());
-    /// let num = BigInt::try_new(vec![1, 2, 3, 4], -10);
-    /// assert!(num.is_err());
-    /// ```
-    ///
-    pub fn try_new(data: Vec<u8>, sign: i8) -> Result<Self, String> {
-        // EXERCISE:
-        // We don't check for trailing 0s but maybe this could be an exercise.
-        // Also we should check numbers are between 0 and 9.
-        if sign == 1 || sign == -1 {
-            Ok(BigInt { data, sign })
-        } else {
-            Err(String::from("Invalid sign."))
-        }
-    }
-}
-
-impl Clone for BigInt {
-    fn clone(&self) -> Self {
-        BigInt {
-            data: self.data.clone(),
-            sign: self.sign,
-        }
-    }
-}
-
-impl Minimum for BigInt {
-    // EXERCISE: Correct this function by using clippy and let it guide you.
-    //           Get inspiration from Display to compute the Minimum
-    fn min(self, rhs: Self) -> Self {
-        if self.sign < rhs.sign {
-            return self;
-        } else if self.sign > rhs.sign {
-            return rhs;
-        }
-        if self.data.len() < rhs.data.len() {
-            return self;
-        } else if self.data.len() > rhs.data.len() {
-            return rhs;
-        }
-        for (l, r) in self.data.iter().rev().zip(rhs.data.iter().rev()) {
-            let ls = (*l as i8) * self.sign;
-            let rs = (*r as i8) * self.sign;
-            if ls < rs {
-                return self;
-            } else if ls > rs {
-                return rhs;
-            }
-        }
-        self
-    }
-}
-
-impl PartialEq for BigInt {
-    fn eq(&self, other: &Self) -> bool {
-        if self.sign == other.sign && self.data.len() == other.data.len() {
-            self.data
-                .iter()
-                .zip(other.data.iter())
-                .try_fold(true, |_, (l, r)| if l == r { Some(true) } else { None })
-                .is_some()
-        } else {
-            false
-        }
-    }
-}
-
-impl std::fmt::Display for BigInt {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        // This could be replaced by an `?`
-        if self.sign == -1 {
-            if let Err(e) = write!(f, "-") {
-                return Err(e);
-            }
-        }
-
-        // This could be replaced by an `?`
-        let res = self
-            .data
-            .iter()
-            .rev()
-            .try_fold((), |_, t| write!(f, "{}", t));
-        res
-    }
-}
-
-// EXERCISE: write tests
-// EXERCISE: Modify Minimum trait to take references?
-
-#[cfg(test)]
-mod tests {}
diff --git a/codes/rust_lang/part08/src/binary_operator.rs b/codes/rust_lang/part08/src/binary_operator.rs
new file mode 100644
index 0000000000000000000000000000000000000000..ab79386998a0f5f664273f93ae6a9f801e6fc84e
--- /dev/null
+++ b/codes/rust_lang/part08/src/binary_operator.rs
@@ -0,0 +1,71 @@
+// ANCHOR: binary_operator
+pub type BinaryOperator<T> = fn(T, T) -> T;
+// ANCHOR_END: binary_operator
+
+/// Returns a closure that computes the minimum
+/// between two elements of type T.
+/// # Example
+///
+/// ```
+/// # use part08::binary_operator::{minimum_operator};
+/// # fn main() {
+/// let f = minimum_operator();
+/// assert!(f(1,2) == 1);
+/// # }
+/// ```
+// ANCHOR: minimum_operator
+pub fn minimum_operator<T: PartialOrd>() -> BinaryOperator<T> {
+    |x: T, y: T| if x <= y { x } else { y }
+}
+// ANCHOR_END: minimum_operator
+
+/// Returns a closure that computes the maximum
+/// between two elements of type T.
+/// # Example
+///
+/// ```
+/// # use part08::binary_operator::{maximum_operator};
+/// # fn main() {
+/// let f = maximum_operator();
+/// assert!(f(1,2) == 2);
+/// # }
+/// ```
+// ANCHOR: maximum_operator
+pub fn maximum_operator<T: PartialOrd>() -> BinaryOperator<T> {
+    |x: T, y: T| if x >= y { x } else { y }
+}
+// ANCHOR_END: maximum_operator
+
+/// Returns a closure that computes the sum
+/// of two elements of type T.
+/// # Example
+///
+/// ```
+/// # use part08::binary_operator::{sum_operator};
+/// # fn main() {
+/// let f = sum_operator();
+/// assert!(f(1,2) == 3);
+/// # }
+/// ```
+// ANCHOR: sum_operator
+pub fn sum_operator<T: std::ops::Add<Output = T>>() -> BinaryOperator<T> {
+    |x: T, y: T| x + y
+}
+// ANCHOR_END: sum_operator
+
+/// Returns a closure that computes the product
+/// of two elements of type T.
+/// # Example
+///
+/// ```
+/// # use part08::binary_operator::{mul_operator};
+/// # fn main() {
+/// let f = mul_operator();
+/// assert!(f(1,2) == 2);
+/// # }
+/// ```
+// ANCHOR: mul_operator
+pub fn mul_operator<T: std::ops::Mul<Output = T>>() -> BinaryOperator<T> {
+    |x: T, y: T| x * y
+}
+// ANCHOR_END: mul_operator
diff --git a/codes/rust_lang/part08/src/custom_int.rs b/codes/rust_lang/part08/src/custom_int.rs
deleted file mode 100644
index fa151502b3231e4212b659332e02f3b9e826d2f0..0000000000000000000000000000000000000000
--- a/codes/rust_lang/part08/src/custom_int.rs
+++ /dev/null
@@ -1,117 +0,0 @@
-use crate::minimum::Minimum;
-
-/// Larger ints based on a [Vec] of [u8] to repensent arbitrary lengthy numbers.
-/// The number has a sign as well.
-pub struct CustomInt {
-    /// The data contains the unsigned integers that are read from right to left
-    /// The number 1337 is stored as vec![7, 3, 3, 1]. Each number must be in the range [0,9]
-    /// and no trailing 0s are allowed.
-    data: Vec<u8>,
-    /// Contains the sign of the number +/-1;
-    sign: i8,
-}
-
-impl CustomInt {
-    /// Tries to create a new [CustomInt]. If the number is valid it returns
-    /// an Ok(CustomInt) an Error otherwise.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use part08::custom_int::CustomInt;
-    /// let num = CustomInt::try_new(vec![1, 2, 3, 4], 1);
-    /// assert!(num.is_ok());
-    /// let num = CustomInt::try_new(vec![1, 2, 3, 4], -1);
-    /// assert!(num.is_ok());
-    /// let num = CustomInt::try_new(vec![1, 2, 3, 4], 10);
-    /// assert!(num.is_err());
-    /// let num = CustomInt::try_new(vec![1, 2, 3, 4], -10);
-    /// assert!(num.is_err());
-    /// ```
-    ///
-    pub fn try_new(data: Vec<u8>, sign: i8) -> Result<Self, String> {
-        // EXERCISE:
-        // We don't check for trailing 0s but maybe this could be an exercise.
-        // Also we should check numbers are between 0 and 9.
-        if sign == 1 || sign == -1 {
-            Ok(CustomInt { data, sign })
-        } else {
-            Err(String::from("Invalid sign."))
-        }
-    }
-}
-
-impl Clone for CustomInt {
-    fn clone(&self) -> Self {
-        CustomInt {
-            data: self.data.clone(),
-            sign: self.sign,
-        }
-    }
-}
-
-impl Minimum for CustomInt {
-    // EXERCISE: Correct this function by using clippy and let it guide you.
-    //           Get inspiration from Display to compute the Minimum
-    fn min(self, rhs: Self) -> Self {
-        if self.sign < rhs.sign {
-            return self;
-        } else if self.sign > rhs.sign {
-            return rhs;
-        }
-        if self.data.len() < rhs.data.len() {
-            return self;
-        } else if self.data.len() > rhs.data.len() {
-            return rhs;
-        }
-        for (l, r) in self.data.iter().rev().zip(rhs.data.iter().rev()) {
-            let ls = (*l as i8) * self.sign;
-            let rs = (*r as i8) * self.sign;
-            if ls < rs {
-                return self;
-            } else if ls > rs {
-                return rhs;
-            }
-        }
-        self
-    }
-}
-
-impl PartialEq for CustomInt {
-    fn eq(&self, other: &Self) -> bool {
-        if self.sign == other.sign && self.data.len() == other.data.len() {
-            self.data
-                .iter()
-                .zip(other.data.iter())
-                .try_fold(true, |_, (l, r)| if l == r { Some(true) } else { None })
-                .is_some()
-        } else {
-            false
-        }
-    }
-}
-
-impl std::fmt::Display for CustomInt {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        // This could be replaced by an `?`
-        if self.sign == -1 {
-            if let Err(e) = write!(f, "-") {
-                return Err(e);
-            }
-        }
-
-        // This could be replaced by an `?`
-        let res = self
-            .data
-            .iter()
-            .rev()
-            .try_fold((), |_, t| write!(f, "{}", t));
-        res
-    }
-}
-
-// EXERCISE: write tests
-// EXERCISE: Modify Minimum trait to take references?
-
-#[cfg(test)]
-mod tests {}
diff --git a/codes/rust_lang/part08/src/find.rs b/codes/rust_lang/part08/src/find.rs
new file mode 100644
index 0000000000000000000000000000000000000000..0d61d8eca1d8b755ec5b99b6ffc7e631b4e963b3
--- /dev/null
+++ b/codes/rust_lang/part08/src/find.rs
@@ -0,0 +1,35 @@
+//! Contains the core logic of the library, allowing to tore generic values
+//! (or their absence) and manipulate them.
+//! We demonstrates three kind of way to deal with errors
+
+use crate::binary_operator::BinaryOperator;
+
+/// Computes the result of a binary reduction of an Array of a type T.
+/// Take the binary operation as a function.
+/// Returns a [Option::Some] containing the the result value
+/// or [Option::None] if the array was empty value was found.
+///
+/// # Example
+///
+/// ```
+/// # use part08::find::{find_with_hof};
+/// # fn main() {
+/// let tab = [10, 32, 12, 43, 52, 53, 83, 2, 9];
+/// let min = find_with_hof(&tab,|x, y| if x <= y { x } else { y });
+/// assert!(min == Some(2));
+/// # }
+/// ```
+// ANCHOR: find_with_hof
+pub fn find_with_hof<T: Copy>(tab: &[T], op: BinaryOperator<T>) -> Option<T> {
+    let mut res = None;
+    // Here is T is Copyable. Which means that t is not moved in the loop
+    for t in tab {
+        if let Some(val) = res {
+            res = Some(op(val, *t))
+        } else {
+            res = Some(*t)
+        }
+    }
+    res
+}
+// ANCHOR_END: find_with_hof
diff --git a/codes/rust_lang/part08/src/io.rs b/codes/rust_lang/part08/src/io.rs
index 482df9d6e0fa6240028d607a081cb060aed74387..7a495499e8a65204e982f16093fabdf1cfb5251a 100644
--- a/codes/rust_lang/part08/src/io.rs
+++ b/codes/rust_lang/part08/src/io.rs
@@ -1,57 +1,23 @@
-use std::io::BufRead;
+//! Contains functions to interact with the user, either
+//! by reading inputs from the terminal, either by writing values
+//! in it.
 
-use crate::custom_int::CustomInt;
-
-/// Reads i32 from the command line and returns a [Vec] containing
-/// these numbers. Returns errors when the parsing fails.
-pub fn read_command_line() -> Result<Vec<i32>, String> {
-    let mut v = Vec::new();
-    let stdin = std::io::stdin();
-    println!("Enter a list of numbers, one per line. End with Ctrl-D (Linux) or Ctrl-Z (Windows).");
-
-    for line in stdin.lock().lines() {
-        let line = match line {
-            Ok(l) => l,
-            Err(_) => {
-                return Err(String::from("Could not read line"));
-            }
-        };
-
-        match line.trim().parse::<i32>() {
-            Ok(num) => v.push(num),
-            Err(_) => {
-                return Err(String::from("Could not parse integer"));
-            }
-        }
-    }
-    Ok(v)
+/// Poorly emulates the parsing of a command line.
+pub fn read_command_line_correct() -> [i32; 9] {
+    [10, 32, 12, 43, 52, 53, 83, 2, 9]
 }
 
-// EXERCISE: Rewrite using ?
-pub fn read_command_line_custom_int() -> Result<Vec<CustomInt>, String> {
-    let v = vec![
-        CustomInt::try_new(vec![1, 3, 6, 9], 1).unwrap(),
-        CustomInt::try_new(vec![2, 4, 2, 1], -1).unwrap(),
-        CustomInt::try_new(vec![7, 4, 5, 3], 1).unwrap(),
-        CustomInt::try_new(vec![4, 1, 1, 1], -1).unwrap(),
-    ];
-    Ok(v)
+/// Poorly emulates the parsing of a command line.
+pub fn read_empty_command_line() -> [i32; 0] {
+    []
 }
 
 /// Prints all the elements of the `tab`.
 /// Tab is borrowed here
-pub fn print_tab(tab: &Vec<i32>) {
+pub fn print_tab(tab: &[i32]) {
+    print!("[ ");
     for t in tab {
         print!("{} ", t);
     }
-    println!();
-}
-
-/// Prints all the elements of the `tab`.
-/// Tab is borrowed here
-pub fn print_tab_custom_int(tab: &Vec<CustomInt>) {
-    for i in tab {
-        println!("{i} ");
-    }
-    println!();
+    println!("]");
 }
diff --git a/codes/rust_lang/part08/src/lib.rs b/codes/rust_lang/part08/src/lib.rs
index ac338352b68eb4d8969338dd79c3da95fa16d62c..4a39e25e46205866eab21af718ed13f74a772a14 100644
--- a/codes/rust_lang/part08/src/lib.rs
+++ b/codes/rust_lang/part08/src/lib.rs
@@ -1,67 +1,66 @@
-/*!
-part08 illustrates the use of [Vec] and the Error Handling with [Option] and [Result].
-It also showcases struct enums.
-*/
+//! This crate shows us different ways of dealing with errors in a Rust program.
+//! You will find examples of [Option], [Result] and [panic!].
 
-pub mod custom_int;
+pub mod binary_operator;
+pub mod find;
 pub mod io;
-mod minimum;
-pub mod something_or_nothing;
 
 #[cfg(test)]
 mod tests {
-    use crate::minimum::Minimum;
-    use crate::something_or_nothing::{find_min, SomethingOrNothing};
+    use crate::binary_operator::*;
+    use crate::find::find_with_hof;
+    const TAB: [i32; 9] = [10, 32, 12, 43, 52, 53, 83, 2, 9];
+    const TAB_EMPTY: [i32; 0] = [];
+    const MIN_TAB: i32 = 2;
+    const MAX_TAB: i32 = 83;
 
     #[test]
-    fn test_creation() {
-        let n1: SomethingOrNothing<i32> = SomethingOrNothing::default();
-        assert!(n1 == SomethingOrNothing::default());
-        let n2: SomethingOrNothing<i32> = SomethingOrNothing::new(1);
-        assert!(n2 == SomethingOrNothing::new(1));
+    fn test_find_with_option_min() {
+        let min: Option<i32> = find_with_hof(&TAB, |x: i32, y: i32| if x <= y { x } else { y });
+
+        assert!(min == Some(MIN_TAB));
+    }
+
+    #[test]
+    fn test_find_with_option_max() {
+        let max: Option<i32> = find_with_hof(&TAB, |x: i32, y: i32| if x >= y { x } else { y });
+
+        assert!(max == Some(MAX_TAB));
     }
 
     #[test]
-    #[should_panic]
-    fn test_failure_creation() {
-        let n2: SomethingOrNothing<i32> = SomethingOrNothing::new(1);
-        assert!(n2 == SomethingOrNothing::default());
-        assert!(n2 == SomethingOrNothing::new(2));
+    fn test_find_with_option_empty() {
+        let min: Option<i32> =
+            find_with_hof(&TAB_EMPTY, |x: i32, y: i32| if x <= y { x } else { y });
+
+        assert!(min.is_none());
     }
 
     #[test]
-    fn test_min() {
-        let a = vec![1, 5, -1, 2, 0, 10, 11, 0, 3];
-        let min = find_min(&a);
-        assert!(min == SomethingOrNothing::new(-1));
+    fn test_minimum_operator() {
+        let f = minimum_operator::<i32>();
+
+        assert!(f(5, 10) == 5);
     }
 
     #[test]
-    fn test_min_empty() {
-        let a: Vec<i32> = vec![];
-        let min = find_min(&a);
-        assert!(min == SomethingOrNothing::default());
+    fn test_maximum_operator() {
+        let f = maximum_operator::<i32>();
+
+        assert!(f(5, 10) == 10);
     }
 
     #[test]
-    fn test_min_i32() {
-        let x = 5;
-        let y = 10;
-        assert_eq!(Minimum::min(x, y), x);
-        assert_eq!(Minimum::min(y, x), x);
-        assert_eq!(Minimum::min(x, x), x);
-        assert_eq!(Minimum::min(y, y), y);
+    fn test_sum_operator() {
+        let f = sum_operator::<i32>();
+
+        assert!(f(5, 10) == 15);
     }
 
     #[test]
-    fn test_min_something_or_nothing() {
-        let x = SomethingOrNothing::new(5i32);
-        let y = SomethingOrNothing::new(10i32);
-        let z = SomethingOrNothing::default();
-        assert!(x.min(y) == x);
-        assert!(y.min(x) == x);
-        assert!(z.min(y) == y);
-        assert!(y.min(z) == y);
-        assert!(z.min(z) == z);
+    fn test_mul_operator() {
+        let f = mul_operator::<i32>();
+
+        assert!(f(5, 10) == 50);
     }
 }
diff --git a/codes/rust_lang/part08/src/main.rs b/codes/rust_lang/part08/src/main.rs
index 1908de7c9f8125639a927f76a5cd61dabf48efe9..2d1d90ebccbeec5cdd8a47758b55c93aa2246a38 100644
--- a/codes/rust_lang/part08/src/main.rs
+++ b/codes/rust_lang/part08/src/main.rs
@@ -1,16 +1,47 @@
+use part08::binary_operator::{minimum_operator, sum_operator};
+use part08::find::find_with_hof;
 use part08::io;
-use part08::something_or_nothing::find_min;
 
-fn main() -> Result<(), String> {
-    let tab = match io::read_command_line_custom_int() {
-        Ok(tab) => tab,
-        Err(s) => return Err(s),
-    };
-    println!("Among the custom ints in the list:");
-    io::print_tab_custom_int(&tab);
-    // There are alternatives to access fields of tuples
-    let min = find_min(&tab);
-    // The first field is not used therefore we can replace it with "_"
-    min.print();
-    Ok(())
+fn main() {
+    let tab = io::read_command_line_correct();
+    println!("Among the elements in the list:");
+    io::print_tab(&tab);
+
+    //ANCHOR: min_usage
+    let min = find_with_hof(&tab, minimum_operator());
+    match min {
+        Some(val) => println!("The minimum value is {}", val),
+        None => eprintln!("There is no minimum"),
+    }
+    //ANCHOR_END: min_usage
+
+    //ANCHOR: max_variable
+    let max_op: fn(i32, i32) -> i32 = |x, y| if x >= y { x } else { y };
+    //ANCHOR_END: max_variable
+
+    //ANCHOR: option_filter
+    let max_val: Option<i32> = find_with_hof(&tab, max_op);
+    let odd_max: Option<i32> = max_val.filter(|x| x % 2 == 1);
+    match odd_max {
+        Some(_) => println!("The maximum value is an odd number"),
+        None => {
+            if max_val.is_some() {
+                println!("The maximum value is an even number")
+            } else {
+                eprintln!("There is no maximum")
+            }
+        }
+    }
+    //ANCHOR_END: option_filter
+
+    //ANCHOR: option_map
+    let two: f32 = 2.0f32;
+
+    let sum: Option<i32> = find_with_hof(&tab, sum_operator());
+    let half: Option<f32> = sum.map(|x: i32| (x as f32) / two);
+    match half {
+        Some(val) => println!("The sum of the elements divided by two is {}", val),
+        None => eprintln!("There is no sum"),
+    }
+    //ANCHOR_END: option_map
 }
diff --git a/codes/rust_lang/part08/src/minimum.rs b/codes/rust_lang/part08/src/minimum.rs
deleted file mode 100644
index fd524a1b6d36c0f09f39d78854f93ba69cfc730b..0000000000000000000000000000000000000000
--- a/codes/rust_lang/part08/src/minimum.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-// If we remove Copy, we have a problem with the t in tab
-// in the computation of the minimum.
-pub trait Minimum: Clone {
-    fn min(self, rhs: Self) -> Self;
-}
-
-impl Minimum for i32 {
-    fn min(self, rhs: Self) -> Self {
-        if self < rhs {
-            self
-        } else {
-            rhs
-        }
-    }
-}
diff --git a/codes/rust_lang/part08/src/something_or_nothing.rs b/codes/rust_lang/part08/src/something_or_nothing.rs
deleted file mode 100644
index ce9af04719e495fb0a2341c929cfe3ba3becd22b..0000000000000000000000000000000000000000
--- a/codes/rust_lang/part08/src/something_or_nothing.rs
+++ /dev/null
@@ -1,78 +0,0 @@
-use std::fmt::Display;
-
-use crate::minimum::Minimum;
-
-/// An generic enumerated type that encapsulates and Option<T>.
-#[derive(Clone, Copy)]
-pub struct SomethingOrNothing<T>(Option<T>);
-
-impl<T: Minimum + Display> SomethingOrNothing<T> {
-    pub fn new(val: T) -> Self {
-        SomethingOrNothing(Some(val))
-    }
-    /// A static function that prints the content of a SomethingOrNothing.
-    pub fn print(&self) {
-        match &self.0 {
-            None => println!("Nothing."),
-            Some(val) => println!("Something is: {}", val),
-        }
-    }
-}
-
-impl<T> Default for SomethingOrNothing<T> {
-    /// By Default a [SomethingOrNothing] is a nothing.
-    fn default() -> Self {
-        SomethingOrNothing(None)
-    }
-}
-
-impl<T: PartialEq + Minimum> PartialEq for SomethingOrNothing<T> {
-    fn eq(&self, other: &Self) -> bool {
-        match (&self.0, &other.0) {
-            (None, None) => true,
-            (Some(lhs), Some(rhs)) => lhs == rhs,
-            _ => false,
-        }
-    }
-}
-
-impl<T: Minimum + Display> Minimum for SomethingOrNothing<T> {
-    fn min(self, rhs: Self) -> Self {
-        match (self.0, rhs.0) {
-            (None, None) => SomethingOrNothing(None),
-            (Some(lhs), Some(rhs)) => SomethingOrNothing::new(lhs.min(rhs)),
-            (None, Some(rhs)) => SomethingOrNothing::new(rhs),
-            (Some(lhs), None) => SomethingOrNothing::new(lhs),
-        }
-    }
-}
-
-/// Computes the minimum of an Array of a type T which implements the [Minimum] trait.
-/// Returns a [Some] containing the the minimum value
-/// or [None] if no minimum value was found.
-///
-/// # Examples
-///
-/// ```
-/// # use part08::something_or_nothing::{SomethingOrNothing, find_min};
-/// # fn main() {
-/// let tab = vec![10, 32, 12, 43, 52, 53, 83, 2, 9];
-/// let min = find_min(&tab);
-/// assert!(min == SomethingOrNothing::new(2));
-/// # }
-/// ```
-///
-/// ```
-/// # use part08::something_or_nothing::{SomethingOrNothing, find_min};
-/// # fn main() {
-/// let tab: Vec<i32> = vec![];
-/// let min = find_min(&tab);
-/// assert!(min == SomethingOrNothing::default());
-/// # }
-/// ```
-pub fn find_min<T: Minimum + Display>(tab: &Vec<T>) -> SomethingOrNothing<T> {
-    // A very elegant fold applied on an iterator
-    tab.iter().fold(SomethingOrNothing::default(), |res, x| {
-        res.min(SomethingOrNothing::new(x.clone()))
-    })
-}
diff --git a/slides/src/SUMMARY.md b/slides/src/SUMMARY.md
index 90da9f734a904dafe45661ccde7ca0c2f6db0346..4c9d844f78e95c27c12bb90dd5991243f695e400 100644
--- a/slides/src/SUMMARY.md
+++ b/slides/src/SUMMARY.md
@@ -11,6 +11,7 @@
 - [Ownership](ownership.md).
 - [Commentaires](commentaires.md).
 - [Gestion d'erreurs](errors.md).
+- [Les closures](closures.md)
 - [Méthodes](methods.md).
 - [Pointeurs intelligents](smart_pointers.md).
 - [Génériques](generics.md).
@@ -22,4 +23,3 @@
 - [Unsafe Rust](collections.md).
 - [Lifetimes](lifetimes.md). -->
 - [Unsafe](unsafe.md).
-
diff --git a/slides/src/closures.md b/slides/src/closures.md
new file mode 100644
index 0000000000000000000000000000000000000000..f0bc47f52c938756a7619f3fe477f07d204708c3
--- /dev/null
+++ b/slides/src/closures.md
@@ -0,0 +1,132 @@
+# Les closures
+
+## Les fonctions anonymes
+
+Les fonctions standards
+
+```rust
+fn foo(x: f32,y: f32) -> f32 {
+    (x * y) / (x + y)
+}
+```
+Les fonctions anonymes
+```rust 
+fn main() {
+    let a = |x: f32, y: f32| -> f32 { (x * y) / (x + y) };
+    let b = |x: f32, y: f32| (x * y) / (x + y);
+}
+```
+
+## Les fonctions d'ordre supérieur
+
+Fonction qui prend une fonction en argument
+
+```rust
+fn foo(f: fn (i32) -> i32) -> i32 {
+    f(5)
+}
+```
+
+Fonction qui retourne une fonction
+
+```rust
+fn bar() -> fn (i32) -> i32 {
+    |x| x+1
+}
+```
+
+## Closures
+
+Capture de la variable `a` dans l'environnement de `b` 
+```rust
+fn main() {
+    let a: Option<i32> = Some(12);
+    let b = |x: bool| x ^ a.is_some();
+    println!("{}", b(true));
+}
+```
+## Le trait Fn 1/3
+
+Problème ?
+
+```rust compile_fail
+fn foo(f:fn (i32) -> i32) -> i32 {
+    f(5)
+}
+fn main() {
+    let a: Option<i32> = Some(12);
+    let b = |x: i32| x + a.unwrap();
+    println!("{}", foo(b));
+}
+```
+
+## Le trait Fn 2/3
+
+```console
+Compiling playground v0.0.1 (/playground)
+error[E0308]: mismatched types
+ --> src/main.rs:7:24
+  |
+6 |     let b = |x:i32| x + a.unwrap();
+  |             ------- the found closure
+7 |     println!("{}", foo(b));
+  |                    --- ^ expected fn pointer, found closure
+  |                    |
+  |                    arguments to this function are incorrect
+  |
+  = note: expected fn pointer `fn(i32) -> i32`
+                found closure `[closure@src/main.rs:6:13: 6:20]`
+note: closures can only be coerced to `fn` types if they do not capture any variables
+ --> src/main.rs:6:25
+  |
+6 |     let b = |x:i32| x + a.unwrap();
+  |                         ^ `a` captured here
+note: function defined here
+ --> src/main.rs:1:4
+  |
+1 | fn foo(f:fn (i32) -> i32) -> i32 {
+  |    ^^^ -----------------
+
+For more information about this error, try `rustc --explain E0308`.
+```
+
+## Le trait Fn 3/3
+
+```rust
+fn foo<F: Fn (i32) -> i32>(f: F) -> i32 {
+    f(5)
+}
+fn main() {
+    let a: Option<i32> = Some(12);
+    let b = |x:i32| x + a.unwrap();
+    println!("{}", foo(b));
+}
+```
+
+## Exemple avec les options 1/2
+
+La fonction map
+
+```rust
+fn main() {
+    let a: Option<i32> = Some(12);
+    println!("{}", a.map(|x| x * 2).unwrap());
+
+    let b: Option<i32> = None;
+    println!("{}", b.map(|x| x * 2).is_some());
+}
+```
+
+## Exemple avec les options 2/2
+
+La fonction filter
+
+```rust
+fn main() {
+    let a: Option<i32> = Some(12);
+    println!("{}", a.filter(|x| x % 6 == 1).is_none());
+
+    let b: Option<i32> = None;
+    println!("{}", b.filter(|x| x % 6 == 0).is_some());
+}
+```
\ No newline at end of file