MonetJS - Maybe Monad
Donc la derniĂšre fois nous avons parlĂ© de la monade Identity avec le framework monet.js (monet.js - Maybe Monad). Pour ce Dimanche matin, je vais faire une 2Ăšme partie un peu plus courte oĂč je vais vous parler de Maybe.
Maybe?
Quâest-ce quâune Maybe? Pensez Ă un type qui peut changer de type đ ou Ă un type qui a 2 sous types. En fait une Maybe est une âboĂźteâ đŠ qui contient une valeur (comme un container donc), et elle (la boĂźte) peut ĂȘtre de type None
, câest Ă dire que sa valeur est nulle ou de type Some
, câest Ă dire que sa valeur nâest pas nulle. ConcrĂštement la Maybe est faite pour aider Ă gĂ©rer les null(s)
et nous Ă©viter pas mal dâexceptions/erreur, ⊠En fait câest la mĂȘme chose que le type Option
en Scala ou Java.
Utilisation
Voici quelques exemples simples pour montrer le fonctionnement de base:
Constructor(s)
let maybe = monet.Maybe.Some(42)
console.log(
maybe.isSome(), // == true
maybe.isNone() // == false
)
ou bien:
let maybe = monet.Maybe.None()
console.log(
maybe.isSome(), // == false
maybe.isNone() // == true
)
Mais lorsque lâon ne sait pas Ă lâavance si lâon va avoir null
ou pas on utilise fromNull
(une factory de Maybe):
let maybe = monet.Maybe.fromNull(42)
console.log(
maybe.isSome(), // == true
maybe.isNone() // == false
)
Obtenir la valeur dâune Maybe: orSome
Une Maybe nâa pas de mĂ©thode get
, Ă la place nous avons orSome
:
let maybe = monet.Maybe.fromNull("đ")
console.log(
maybe.orSome("đĄ") // maybe.orSome("đĄ") == đ
)
ou dans le cas dâun None
:
let maybe = monet.Maybe.fromNull(null)
console.log(
maybe.orSome("đĄ") // maybe.orSome("đĄ") == đĄ
)
Obtenir une Maybe dâune Maybe: orElse
orElse
ne retourne pas une valeur mais une Maybe:
dans le cas dâun Some
let maybe = monet.Maybe.fromNull("đ")
let newMaybe = maybe.orElse(monet.Maybe.Some("đ€ą"))
console.log(
newMaybe, // { isValue: true, val: 'đ' }
newMaybe.isSome() // == true
)
dans le cas dâun None
let maybe = monet.Maybe.fromNull(null)
let newMaybe = maybe.orElse(monet.Maybe.Some("đ€ą"))
console.log(
newMaybe, // { isValue: true, val: 'đ€ą' }
newMaybe.isSome() // == true
)
â ïž Donc orElse
retourne la Maybe initiale si câest un Some
ou la Maybe proposée si un None
.
Ok, et en vrai, à quoi ça pourrait me servir?
⊠Pensez à une recherche en base de données:
let users = [
{id:1, name:"bob", avatar:"đŒ"}
, {id:2, name:"sam", avatar:"đ»"}
, {id:3, name:"jane", avatar:"đ°"}
, {id:4, name:"john", avatar:"đ±"}
]
let getUserById = id => monet.Maybe.fromNull(users.find(u => u.id == id))
console.log(
getUserById(3) // { isValue: true, val: { id: 3, name: 'jane', avatar: 'đ°' } }
)
console.log(
getUserById(6) // { isValue: false, val: null }
)
Dans le 1er cas jâobtiens un Some
, sans le 2Ăšme un None
⊠ok ⊠Mais comme câest une monade, nous avons la mĂ©thode map
âïž et on peut faire plein de choses sympas
Maybe et map()
Avant, pour obtenir lâavatar dâun utilisateur que lâon cherche par son id
, on aurait fait quelaue chose comme ceci:
users.find(u => u.id == 6).avatar
Et comme lâutilisateur nâexiste pas, on obtient un joli:
TypeError: Cannot read property 'avatar' of undefined
Qui nâa jamais oubliĂ© de tester si il avait rĂ©cupĂ©rĂ© quelque chose ou pas avant de jouer avec dans son code âïž. Mais maintenant, vous pouvez faire ceci:
let getUserById = id => monet.Maybe.fromNull(users.find(u => u.id == id))
let getAvatar = u => u.avatar
console.log("display avatar of 2:",
getUserById(2).map(getAvatar).orSome("đ»")
)
console.log("display avatar of 6:",
getUserById(6).map(getAvatar).orSome("đ»") // be careful Number six doesn't exist ... I'm not a number, I'm a free man!
)
et vous obtiendrez ceci:
display avatar of 2: đ»
display avatar of 6: đ»
et sans âplantageâ âïžđ
getUserById
me retourne une monade Maybe M1- avec
map
je peux appliquer une transformation Ă la valeur M1 (sans la modifier) - et obtenir une nouvelle monade Maybe M2
- sur laquelle je peux faire un
orSome
- âïž donc plus de plantage idiot dans une recherche dans une base de donnĂ©es, collections, âŠ
Un dernier pour la route đ·
Une chose que jâadore â€ïž avec la Maybe, câest le catamorphisme đ€Š (allez faire un tour ici https://fr.wikipedia.org/wiki/Catamorphisme ça pique đ” hein?). Plus simplement (et mĂȘme si Ă©tymologiquement parlant câest tirĂ© par les đ), pensez Ă catastrophe.
Dans monet.js la Maybe a une méthode cata
qui va vous permettre de gérer les catastrophe. Cette méthode prend 2 arguments (en fait 2 callbacks ou 2 closures, appelez les comme vous le sentez), cata(left(), right(value))
:
- le 1Ăšr callback, que lâon appellera
left
(lâargument le plus Ă gauche) qui ne prend aucune valeur en argument et qui est appelĂ© quand la Maybe est unNone
- le 2Ăšme callback, que lâon appellera
right
, qui prend comme argument la valeur de la Maybe quand câest unSome
â ïž right
est aussi un moyen mĂ©motechnique: right comme juste, âcâest ok, tu as tout juste đâ.
Mais avec un petit bout de code ce sera plus parlant, rappelez vous de notre getUserById
qui nous retourne une Maybe:
console.log(
getUserById(3).cata(
()=> {
return "this đĄ does not exist"
},
(user) => {
return `Hello ${user.avatar}`
}
)
)
Dans ce cas lĂ , nous obtiendrons: Hello đ°
console.log(
getUserById(6).cata(
()=> {
return "this đĄ does not exist"
},
(user) => {
return `Hello ${user.avatar}`
}
)
)
Dans ce cas lĂ , nous obtiendrons: this đĄ does not exist
Fin de ce chapitre. Maybe est trĂšs pratique, mais dĂšs fois, on aurait besoin quâelle en fasse un tout petit peu plus. Donc la prochaine fois, je vous parlerais de Either
.
Bon Dimanche đ đ° đ·
Tweet