Sfondo
Ho Map[String,String]
dei valori di configurazione. Voglio estrarre una serie di chiavi e fornire messaggi di errore significativi se qualcuno di essi manca. Per esempio:Utilizzo della convalida con | @ | in Scalaz
val a = Map("url"->"http://example.com", "user"->"bob", "password"->"12345")
dire che voglio trasformare questo in una classe case:
case class HttpConnectionParams(url:String, user:String, password: String)
Ora, posso semplicemente utilizzare un ciclo for per estrarre i valori:
for(url <- a.get("url");
user <- a.get("user");
password <- a.get("password")) yield {
HttpConnectionParams(url,user,password)
}
Per prendi un Option[HttpConnectionParams]
. Questo è bello e pulito, tranne se ottengo un None
quindi non so cosa mancasse. Mi piacerebbe fornire queste informazioni.
Validazione con Scalaz
Immettere scalaz. Sto usando la versione 7.1.3.
Da quello che sono riuscito a mettere insieme (un buon riferimento è here) posso usare disgiunzioni:
for(url <- a.get("url") \/> "Url must be supplied";
user <- a.get("user") \/> "Username must be supplied";
password <- a.get("password") \/> "Password must be supplied") yield {
HttpConnectionParams(url,user,password)
}
Questo è bello perché ora ho un messaggio di errore, ma questo è perché railway oriented si ferma al primo fallimento. Cosa succede se voglio ottenere tutti gli errori? Usiamo la convalida e il costruttore applicativa (alias "| @ |"):
val result = a.get("url").toSuccess("Url must be supplied") |@|
a.get("username").toSuccess("Username must be supplied") |@|
a.get("password").toSuccess("Password must be supplied")
result.tupled match {
case Success((url,user,password)) => HttpConnectionParams(url,user,password)
case Failure(m) => println("There was a failure"+m)
}
Domande
Questo fa quello che mi aspetto, ma ho alcune domande circa l'utilizzo:
- Is c'è un'alternativa facile da usare a scalaz per questo caso d'uso? Preferirei non aprire la scatola di Pandora e introdurre lo scalaz se non dovessi farlo.
- Una ragione per cui non vorrei usare lo scalaz è che è davvero molto difficile capire cosa fare se non si conosce l'intero framework come me. Ad esempio, qual è l'elenco di impliciti di cui hai bisogno per far funzionare il codice sopra riportato?
import scalaz._
in qualche modo non ha funzionato per me. [1] Come posso capire questo dai documenti API? - Esiste un modo più sintetico per esprimere il caso di utilizzo della convalida? Sono inciampato fino a quando non sono arrivato a qualcosa che funzionava e non ho idea se ci sono altri modi migliori di fare la stessa cosa in scalaz.
[1] Dopo molta costernazione sono arrivato a questo insieme di importazioni per il caso di utilizzo applicativo. Speriamo che questo aiuta qualcuno:
import scalaz.std.string._
import scalaz.syntax.std.option._
import scalaz.syntax.apply._
import scalaz.Success
import scalaz.Failure
"Una ragione per cui non vorrei usare lo scalaz è che è davvero molto difficile capire cosa fare se non, come me, conosca l'intero framework" - Non dirlo direttamente a Tony Morris;). Scalaz potrebbe non essere la tazza di tè per tutti; c'è una ripida curva di apprendimento coinvolta per capirlo se non sei della persuasione hard FP e/o non hai familiarità con Haskell (ci vuole molta ispirazione da quella lingua). È una libreria potente se sai cosa farne - ho l'impressione che tu la stia battendo perché non puoi preoccuparti di impararla a fondo - non è colpa di Scalaz –
Un'alternativa a Scalaz è Cats. Uno degli obiettivi è di essere più aperto e user friendly rispetto a Scalaz in termini di documentazione ed esempi, anche se ho trovato la comunità Scalaz pronta ad aiutare con qualsiasi problema che ho avuto. –
Sì, un collaboratore ha consigliato i gatti ma alla versione 0.2 è pronto per essere usato da tutti? –