0Pricing
Scala for Backend Engineering & Functional Programming · Lekcja

Monady w Scali

Zrozum monady i dowiedz się, jak umożliwiają sekwencyjne komponowanie obliczeń w sposób funkcyjny.

Monady w Scali to bezpłatna lekcja Scala for Backend Engineering & Functional Programming na CoddyKit. To lekcja 2 z 3. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Scala for Backend Engineering & Functional Programming, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Scala for Backend Engineering & Functional Programming zawiera 3 lekcji w sumie.

Czym są monady?

Monady to podstawowe pojęcie w programowaniu funkcyjnym, często uznawane za zaawansowane. Proszę się nie martwić — wyjaśnimy je w przystępny sposób!

W istocie monady to wzorzec projektowy, który pomaga sekwencjonować obliczenia obejmujące „kontekst”. Można je traktować jako sposób zarządzania efektami ubocznymi lub obsługi wartości, których może brakować, w ramach przewidywalnej struktury.

Łączenie operacji kontekstowych

Wyobraź sobie, że masz wartość, która może istnieć albo nie, na przykład Option[Int]. Jeśli chcesz wykonać na niej kilka operacji, ale tylko wtedy, gdy wartość jest obecna, jak zrobić to w przejrzysty sposób?

Zagnieżdżone instrukcje if szybko stają się nieczytelne. Monady zapewniają przejrzysty, sekwencyjny sposób łączenia tych operacji i automatycznie propagują „kontekst” (na przykład obecność lub brak wartości).

Potęga `flatMap`

Najważniejszą operacją pomocną w zrozumieniu monad jest flatMap.

  • Przyjmuje funkcję, która zwraca inną wartość „kontekstową” (taką jak Option lub List).
  • Stosuje tę funkcję do wartości znajdującej się wewnątrz bieżącego kontekstu.
  • Jeśli kontekst jest pusty (np. None), flatMap po prostu propaguje tę pustkę bez stosowania funkcji.

Dzięki temu można płynnie łączyć operacje, obsługując po drodze potencjalne błędy lub brakujące wartości.

`Option` i `flatMap`

Typ Option w Scali jest doskonałym przykładem monady. Option może mieć wartość Some(value) albo None.

Gdy używasz flatMap na obiekcie Option:

  • Jeśli ma on wartość Some(value), podana funkcja zostaje zastosowana do value, a jej wynik (inne Option) zostaje użyty.
  • Jeśli ma wartość None, funkcja nigdy nie jest wywoływana, a bezpośrednio zwracane jest None.

Dzięki temu operacje są wykonywane tylko wtedy, gdy wartość rzeczywiście jest obecna.

`flatMap` z `Option`

Zobaczmy działanie flatMap na przykładzie Option. Ten kod próbuje przekształcić ciąg znaków na liczbę całkowitą, a następnie ją podwoić, ale tylko wtedy, gdy oba kroki się powiodą.

object Main {
  def parseToInt(s: String): Option[Int] =
    try {
      Some(s.toInt)
    } catch {
      case _: NumberFormatException => None
    }

  def main(args: Array[String]): Unit = {
    val result1 = parseToInt("10").flatMap(x => Some(x * 2))
    val result2 = parseToInt("hello").flatMap(x => Some(x * 2))

    println(s"Result 1: $result1")
    println(s"Result 2: $result2")
  }
}

`List` i `flatMap`

Innym popularnym typem Scali, który zachowuje się jak monada, jest List.

Gdy używasz flatMap na obiekcie List:

  • Podana funkcja jest stosowana do każdego elementu listy.
  • Dla każdego elementu funkcja musi zwrócić nową List.
  • Wszystkie wynikowe listy są następnie łączone w jedną spłaszczoną listę.

Jest to przydatne do przekształcania i łączenia list danych.

`flatMap` z `List`

Oto działanie flatMap na obiekcie List. Zwróć uwagę, jak „spłaszcza” wyniki zastosowania funkcji, która dla każdego elementu zwraca listę.

object Main {
  def main(args: Array[String]): Unit = {
    val numbers = List(1, 2, 3)

    // For each number, create a list of that number and its double
    val result = numbers.flatMap(n => List(n, n * 2))

    println(s"Original: $numbers")
    println(s"FlatMapped: $result")

    val words = List("hello", "world")
    val chars = words.flatMap(_.toList) // Get all characters

    println(s"Words: $words")
    println(s"Chars: $chars")
  }
}

Reguły monad (w uproszczeniu)

Chociaż flatMap jest podstawową operacją, prawdziwa monada musi również przestrzegać pewnych praw (reguł), aby zapewnić przewidywalne zachowanie.

Upraszczając, typ jest monadyczny, jeśli:

  • Potrafi „opakować” wartość (często nazywa się to pure lub unit).
  • Ma operację flatMap, która łączy obliczenia w sposób zachowujący kontekst.

Prawa te zapewniają spójność składania operacji monadycznych, niezależnie od sposobu ich grupowania.

Monady i wyrażenia for

Wyrażenia for-comprehensions w Scali zapewniają cukier składniowy ułatwiający pracę z monadami (i innymi typami, takimi jak funktory i aplikatywy).

Pozwalają pisać sekwencyjne operacje na wartościach kontekstowych w znacznie czytelniejszym stylu, przypominającym kod imperatywny.

W tle kompilator Scali tłumaczy wyrażenia for-comprehensions na serię wywołań flatMap, map i filter.

`Option` w wyrażeniu for

Ten przykład pokazuje, jak wyrażenie for-comprehension może uprościć przedstawiony wcześniej łańcuch wywołań Option.flatMap. Przypadek None jest obsługiwany automatycznie.

object Main {
  def parseToInt(s: String): Option[Int] =
    try {
      Some(s.toInt)
    } catch {
      case _: NumberFormatException => None
    }

  def main(args: Array[String]): Unit = {
    val numStr1 = "10"
    val numStr2 = "5"
    val badStr = "abc"

    val result1 = for {
      a <- parseToInt(numStr1) // If parseToInt returns None, the whole for-comp becomes None
      b <- parseToInt(numStr2)
    } yield a + b

    val result2 = for {
      a <- parseToInt(numStr1)
      b <- parseToInt(badStr) // This will be None
    } yield a + b

    println(s"Sum 1: $result1") // Some(15)
    println(s"Sum 2: $result2") // None
  }
}

Wyzwanie: monady

Rozważ następujący kod Scali.

val list1 = List(1, 2)
val list2 = List(10, 20)

val result = for {
  x <- list1
  y <- list2
} yield x * y

Monady: sekwencjonowanie kontekstowe

Gratulacje! Zrobili Państwo duży krok w kierunku zrozumienia monad.

  • Monady zapewniają zaawansowany wzorzec sekwencjonowania obliczeń wykonywanych w ramach „kontekstu” (na przykład Option dla obecności lub braku wartości oraz List dla wielu wartości).
  • Kluczową operacją jest flatMap, która stosuje funkcję zwracającą nową wartość kontekstową, skutecznie łącząc i spłaszczając konteksty.
  • Wyrażenia for-comprehensions w Scali są doskonałym cukrem składniowym, tłumaczonym bezpośrednio na wywołania flatMap (oraz map/filter), dzięki czemu kod monadyczny staje się znacznie czytelniejszy.

Następnie przyjrzymy się popularnym bibliotekom programowania funkcyjnego, takim jak Cats i ZIO, które szeroko wykorzystują te koncepcje monadyczne.

Często zadawane pytania

Czy lekcja „Monady w Scali” jest bezpłatna?

Tak — pełny tekst „Monady w Scali” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Scala for Backend Engineering & Functional Programming, przejdź na CoddyKit PRO. Kurs Scala for Backend Engineering & Functional Programming zawiera 3 lekcji w sumie.

Co nauczysz się w „Monady w Scali”?

Zrozum monady i dowiedz się, jak umożliwiają sekwencyjne komponowanie obliczeń w sposób funkcyjny. Ćwiczysz Scala for Backend Engineering & Functional Programming z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Scala for Backend Engineering & Functional Programming?

Nie wymagamy żadnego doświadczenia. Scala for Backend Engineering & Functional Programming w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 3.

Ile czasu zajmuje lekcja „Monady w Scali”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Scala for Backend Engineering & Functional Programming?

Tak. Każda lekcja Scala for Backend Engineering & Functional Programming zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Wprowadzenie do Functors i Applicatives
  2. Monady w Scali
  3. Poznajemy Cats i ZIO
← Powrót do Scala for Backend Engineering & Functional Programming