Sono nuovo a FP e Scala e sto leggendo il libro Programmazione funzionale in Scala. Uno degli esercizi del capitolo 4 ci chiede di scrivere una funzione denominata sequence
che converta uno List[Option[A]]
in uno Option[List[A]]
. Qui Option
è una reimplementazione di Option
fornita dalla libreria Scala. Ecco il codice richiesto.Conversione lista [Opzione [A]] a un'opzione [Elenco [A]] in Scala
trait Option[+A] {
/* Function to convert Option[A] to Option[B] using the function passed as an argument */
def map[B](f: A => B): Option[B] = this match {
case None => None
case Some(v) => Some(f(v))
}
/* Function to get the value in `this` option object or return the default value provided. Here,
* `B >: A` denotes that the data type `B` is either a super-type of `A` or is `A`
*/
def getOrElse[B >: A](default: => B): B = this match {
case None => default
case Some(v) => v
}
/* Used to perform (nested) operations on `this` and aborts as soon as the first failure is
* encountered by returning `None`
*/
def flatMap[B](f: A => Option[B]): Option[B] = {
map(f).getOrElse(None)
}
}
case class Some[+A](get: A) extends Option[A] // used when the return value is defined
case object None extends Option[Nothing] // used when the return value is undefined
Ora ho provato un sacco, ma ho dovuto cercare la soluzione per la scrittura sequence
, che è,
def sequence[A](l: List[Option[A]]): Option[List[A]] = l match {
case Nil => Some(Nil) // Or `None`. A design decision in my opinion
case h :: t => h.flatMap(hh => sequence(t).map(hh :: _))
}
voglio solo per assicurarsi che ho capito la soluzione corretta. Quindi ecco le mie domande.
- La mia intuizione sul valore di ritorno per
case Nil
è corretta? È davvero una decisione di progettazione o è in un modo migliore rispetto all'altro? - Per
case h :: t
, questo è quello che ho capito. Passiamo il valoreh
in primo luogo alla funzione anonima inflatMap
(comehh
) che richiama in modo ricorsivosequence
. Questa chiamata ricorsiva disequence
restituisce unOption
che incapsula iOption
s int
. Invochiamomap
su questo valore restituito e passiamo ah
alla funzione anonima (comehh
) che crea quindi un nuovoList[A]
con l'elenco restituito dalla chiamata ricorsiva come coda eh
come capo. Questo valore viene quindi incapsulato inOption
invocandoSome
e restituito.
La mia comprensione per la seconda parte è corretta? Se sì, c'è un modo migliore per spiegarlo?
Il problema con la versione 'fold' è che l'Elenco risultante non mantiene l'ordine; diventa invertito. – borice
Si desidera utilizzare 'sofar: + value' al posto di' value :: sofar' nell'istruzione case per aggiungere alla fine della lista fino ad ora. – borice