0Pricing
Scala for Backend Engineering & Functional Programming · Lezione

Comporre Either

map e flatMap

Comporre Either è una lezione Scala for Backend Engineering & Functional Programming gratuita su CoddyKit. Questa è la lezione 3 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Scala for Backend Engineering & Functional Programming, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Scala for Backend Engineering & Functional Programming include 4 lezioni in totale.

Comporre i calcoli

I programmi reali concatenano diversi passaggi soggetti a errori: analisi, validazione, ricerca e calcolo. Either consente di comporli in modo che il primo errore interrompa l'intera catena.

Gli strumenti sono map, flatMap e le for-comprehension.

flatMap concatena gli Either

flatMap applica una funzione che restituisce a sua volta un Either. Se il ricevente è un Left, la funzione non viene mai chiamata e il Left si propaga.

object Main {
  def positive(n: Int): Either[String, Int] =
    if (n > 0) Right(n) else Left("not positive")

  def main(args: Array[String]): Unit = {
    val r = Right(5).flatMap(positive)
    val l = Right(-1).flatMap(positive)
    println(r)
    println(l)
  }
}

Interruzione anticipata

Quando concatena più chiamate a flatMap, il primo Left interrompe tutto. I passaggi successivi vengono saltati e quell'errore diventa il risultato finale.

object Main {
  def step(label: String, n: Int): Either[String, Int] = {
    println(s"running $label")
    Right(n + 1)
  }

  def main(args: Array[String]): Unit = {
    val result = Left("early error").asInstanceOf[Either[String, Int]]
      .flatMap(n => step("A", n))
      .flatMap(n => step("B", n))
    println(result)
  }
}

For-comprehension su Either

Poiché Either è right-biased, può usarlo in una for-comprehension. Ogni <- estrae un Right; qualsiasi Left interrompe la comprehension e ne diventa il risultato.

object Main {
  def parse(s: String): Either[String, Int] =
    s.toIntOption.toRight(s"bad: $s")

  def main(args: Array[String]): Unit = {
    val sum = for {
      a <- parse("3")
      b <- parse("4")
    } yield a + b
    println(sum)
  }
}

Una for-comprehension con errore

Se un passaggio della comprehension produce un Left, l'intera espressione corrisponde a quel Left e i passaggi successivi non vengono eseguiti.

object Main {
  def parse(s: String): Either[String, Int] =
    s.toIntOption.toRight(s"bad: $s")

  def main(args: Array[String]): Unit = {
    val sum = for {
      a <- parse("3")
      b <- parse("oops")
      c <- parse("5")
    } yield a + b + c
    println(sum)
  }
}

Concatenare le validazioni

Una pipeline realistica: analizzare una stringa, verificare quindi una regola di business e infine trasformare il risultato. Ogni fase restituisce un Either.

object Main {
  def parse(s: String): Either[String, Int] = s.toIntOption.toRight("not a number")
  def checkRange(n: Int): Either[String, Int] =
    if (n >= 1 && n <= 100) Right(n) else Left("out of range")

  def process(s: String): Either[String, Int] =
    parse(s).flatMap(checkRange).map(_ * 10)

  def main(args: Array[String]): Unit = {
    println(process("7"))
    println(process("500"))
    println(process("x"))
  }
}

map a confronto con flatMap

Usi map quando la funzione restituisce un valore semplice. Usi flatMap quando restituisce un altro Either, per evitare un Either[String, Either[String, Int]] annidato.

@main def run(): Unit = {
  val withMap: Either[String, Int] = Right(2).map(_ + 1)
  val nested: Either[String, Either[String, Int]] = Right(2).map(n => Right(n + 1))
  val flat: Either[String, Int] = Right(2).flatMap(n => Right(n + 1))
  println(withMap)
  println(nested)
  println(flat)
}

Combinare valori indipendenti

Una for-comprehension funziona anche quando ogni passaggio non dipende da quello precedente. Tutti i passaggi devono avere esito positivo perché venga eseguito il yield finale.

object Main {
  def parse(s: String): Either[String, Int] = s.toIntOption.toRight(s"bad: $s")

  def main(args: Array[String]): Unit = {
    val combined = for {
      x <- parse("10")
      y <- parse("20")
      z <- parse("30")
    } yield List(x, y, z).sum
    println(combined)
  }
}

Trasformazione degli errori in stile leftMap

La libreria standard Either non dispone di leftMap, ma può trasformare l'errore con swap.map(...).swap oppure eseguendo il mapping all'interno di un fold. In questo modo i tipi di errore rimangono coerenti lungo tutta la pipeline.

@main def run(): Unit = {
  val e: Either[String, Int] = Left("low-level error")
  val mapped = e.swap.map(msg => s"context: $msg").swap
  println(mapped)
}

Mettere tutto insieme

Una piccola pipeline per una calcolatrice che analizza due numeri e li divide, segnalando ogni errore tramite un errore tipizzato.

object Main {
  def parse(s: String): Either[String, Int] = s.toIntOption.toRight(s"bad number: $s")
  def divide(a: Int, b: Int): Either[String, Int] =
    if (b == 0) Left("division by zero") else Right(a / b)

  def calc(x: String, y: String): Either[String, Int] =
    for {
      a <- parse(x)
      b <- parse(y)
      r <- divide(a, b)
    } yield r

  def main(args: Array[String]): Unit = {
    println(calc("20", "4"))
    println(calc("20", "0"))
    println(calc("x", "4"))
  }
}

Perché è importante

La composizione di Either offre una programmazione orientata alle ferrovie: il percorso positivo procede attraverso Right, mentre ogni errore devia sul binario Left e salta il resto. Niente eccezioni, niente controlli sui valori nulli, solo valori.

Verifica rapida

Verifichi la sua comprensione della composizione di Either.

Riepilogo

Ha imparato a comporre Either:

  • flatMap concatena passaggi soggetti a errori e si interrompe al primo Left.
  • Le for-comprehension rendono chiare le pipeline composte da più passaggi.
  • Usi map per i risultati semplici e flatMap per le funzioni che restituiscono Either.
  • Trasformi gli errori con swap.map(...).swap.

Domande Frequenti

La lezione «Comporre Either» è gratuita?

Sì — il testo completo di «Comporre Either» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Scala for Backend Engineering & Functional Programming, passa a CoddyKit PRO. Il corso Scala for Backend Engineering & Functional Programming include 4 lezioni in totale.

Cosa imparerò in «Comporre Either»?

map e flatMap Eserciti Scala for Backend Engineering & Functional Programming con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Scala for Backend Engineering & Functional Programming?

Non è richiesta alcuna esperienza precedente. Scala for Backend Engineering & Functional Programming su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 4.

Quanto tempo richiede la lezione «Comporre Either»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Scala for Backend Engineering & Functional Programming?

Sì. Ogni lezione Scala for Backend Engineering & Functional Programming include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Either per gli errori
  2. Try, Success, Failure
  3. Comporre Either
  4. Convertire tra tipi
← Torna a Scala for Backend Engineering & Functional Programming