0Pricing
Scala for Backend Engineering & Functional Programming · Lekcja

Funkcje wyższego rzędu i currying

Poznaj zaawansowane koncepcje programowania funkcyjnego, takie jak funkcje wyższego rzędu i currying, aby tworzyć elastyczny i wielokrotnego użytku kod.

Funkcje wyższego rzędu i currying 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.

Odblokowywanie funkcji wyższego rzędu

Witamy na lekcji 2! W programowaniu funkcyjnym funkcje mają ogromne możliwości. Służą nie tylko do obliczania wartości — można je również traktować jak dowolne inne dane.

Oznacza to, że funkcje można przekazywać jako argumenty do innych funkcji, a nawet zwracać jako ich wyniki. Funkcja, która to robi, jest nazywana funkcją wyższego rzędu (HOF).

  • Funkcje HOF przyjmują jedną lub więcej funkcji jako argumenty.
  • Funkcje HOF zwracają funkcję jako wynik.
  • Albo robią jedno i drugie!

HOF w praktyce: `map`

Jedną z najczęściej używanych funkcji HOF w Scali jest map. Przekształca ona każdy element kolekcji, stosując do niego określoną funkcję, i zwraca nową kolekcję.

Spróbuj uruchomić ten prosty przykład:

object Main {
  def main(args: Array[String]): Unit = {
    val numbers = List(1, 2, 3)
    val doubledNumbers = numbers.map(x => x * 2)
    println(s"Original: $numbers")
    println(s"Doubled: $doubledNumbers")
  }
}

HOF w praktyce: `filter`

Inną przydatną funkcją HOF jest filter. Wybiera ona z kolekcji elementy spełniające określony warunek (funkcję zwracającą wartość logiczną), tworząc nową kolekcję.

Oto jak można użyć filter do znalezienia liczb parzystych:

object Main {
  def main(args: Array[String]): Unit = {
    val allNumbers = List(1, 2, 3, 4, 5, 6)
    val evenNumbers = allNumbers.filter(x => x % 2 == 0)
    println(s"All: $allNumbers")
    println(s"Even: $evenNumbers")
  }
}

Definiowanie własnej funkcji HOF

Nie trzeba ograniczać się do wbudowanych funkcji HOF! Można definiować własne funkcje, które przyjmują inne funkcje jako parametry. Składnia typu funkcji to (InputType => ReturnType).

Ten przykład definiuje funkcję applyOperation, która przyjmuje wartość typu Int oraz inną funkcję op (przyjmującą wartość typu Int i zwracającą wartość typu Int).

object Main {
  // A HOF that applies an operation to a number
  def applyOperation(x: Int, op: Int => Int): Int = {
    op(x)
  }

  def main(args: Array[String]): Unit = {
    val result = applyOperation(10, _ * 3) // Pass an anonymous function
    println(s"Result of 10 * 3: $result")

    val anotherResult = applyOperation(7, _ + 5)
    println(s"Result of 7 + 5: $anotherResult")
  }
}

Funkcje anonimowe i skrócona składnia

Przekazując funkcje do funkcji HOF, często używa się funkcji anonimowych (nazywanych również lambdami). Scala udostępnia zwięzłe sposoby ich zapisywania.

  • x => x * 2: pełna funkcja anonimowa.
  • _ * 2: skrócona składnia funkcji anonimowej z jednym parametrem.

Obie formy są często używane i sprawiają, że kod jest krótszy oraz bardziej czytelny.

object Main {
  def main(args: Array[String]): Unit = {
    val numbers = List(10, 20, 30)

    // Using full anonymous function syntax
    val dividedByTwo = numbers.map(x => x / 2)
    println(s"Divided by two: $dividedByTwo")

    // Using shorthand `_` syntax
    val plusOne = numbers.map(_ + 1)
    println(s"Plus one: $plusOne")
  }
}

Wprowadzenie do currying

Currying to technika przekształcania funkcji przyjmującej wiele argumentów w sekwencję funkcji, z których każda przyjmuje jeden argument.

Nazwa pochodzi od nazwiska logika Haskella Curry’ego. W Scali funkcje z wieloma listami parametrów są automatycznie poddawane curryingowi.

Zamiast f(arg1, arg2) zapisuje się f(arg1)(arg2).

Przykład currying: wiele list parametrów

Zobaczmy currying w praktyce. Zwróć uwagę, że add przyjmuje argumenty w dwóch oddzielnych listach parametrów.

Dzięki temu można częściowo zastosować funkcję, tworząc nowe funkcje przez ustalenie niektórych argumentów.

object Main {
  // A curried function with two parameter lists
  def add(a: Int)(b: Int): Int = {
    a + b
  }

  def main(args: Array[String]): Unit = {
    // Call the function normally
    println(s"5 + 3 = ${add(5)(3)}")

    // Partially apply the first argument
    val addFive = add(5)_ // `_` tells Scala to treat it as a partially applied function
    println(s"5 + 10 = ${addFive(10)}")
    println(s"5 + 20 = ${addFive(20)}")
  }
}

Zalety currying

Po co używać currying? Ta technika oferuje kilka korzyści w programowaniu funkcyjnym:

  • Częściowe zastosowanie: Tworzenie wyspecjalizowanych wersji funkcji przez ustalenie niektórych argumentów. Zwiększa to możliwość ponownego użycia kodu.
  • Kompozycja funkcji: Funkcje poddane curryingowi często łatwiej łączyć z innymi funkcjami.
  • Wnioskowanie typów: Może czasami ułatwiać wnioskowanie typów w Scali, szczególnie podczas pracy ze złożonymi typami generycznymi.

Currying na potrzeby własnych loggerów

Wyobraźmy sobie, że chcą Państwo utworzyć różne funkcje rejestrowania dla różnych poziomów (np. INFO, ERROR), ale używać tej samej podstawowej logiki. Currying doskonale się do tego nadaje!

Można zdefiniować ogólną funkcję log, a następnie zastosować ją częściowo, aby utworzyć konkretne loggery.

object Main {
  def log(level: String)(message: String): Unit = {
    println(s"[$level] $message")
  }

  def main(args: Array[String]): Unit = {
    // Create specialized loggers using partial application
    val infoLogger = log("INFO")_
    val errorLogger = log("ERROR")_

    infoLogger("User logged in successfully.")
    errorLogger("Failed to connect to database!")
  }
}

Szybkie sprawdzenie: HOF i currying

Rozważmy następujący fragment kodu Scali:

def calculate(x: Int)(y: Int, op: (Int, Int) => Int): Int = {
  op(x, y)
}

val add = (a: Int, b: Int) => a + b
val multiply = (a: Int, b: Int) => a * b

val result1 = calculate(10)(5, add)
val result2 = calculate(2)(3, multiply)

Jakie wartości mają result1 i result2?

Podsumowanie: HOF i currying

Świetna praca! Poznali Państwo dwa ważne pojęcia programowania funkcyjnego:

  • Funkcje wyższego rzędu (HOF): Funkcje, które mogą przyjmować inne funkcje jako argumenty lub zwracać je jako wyniki. Umożliwiają tworzenie elastycznego kodu, który można ponownie wykorzystywać, na przykład z użyciem map i filter.
  • Currying: Technika przekształcania funkcji z wieloma argumentami w sekwencję funkcji, z których każda przyjmuje jeden argument. Doskonale sprawdza się przy częściowym zastosowaniu i tworzeniu wyspecjalizowanych funkcji.

Pojęcia te są podstawą tworzenia wyrazistego i modularnego kodu Scali!

Często zadawane pytania

Czy lekcja „Funkcje wyższego rzędu i currying” jest bezpłatna?

Tak — pełny tekst „Funkcje wyższego rzędu i currying” 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 „Funkcje wyższego rzędu i currying”?

Poznaj zaawansowane koncepcje programowania funkcyjnego, takie jak funkcje wyższego rzędu i currying, aby tworzyć elastyczny i wielokrotnego użytku kod. Ć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 „Funkcje wyższego rzędu i currying”?

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. Funkcje jako wartości pierwszej klasy
  2. Funkcje wyższego rzędu i currying
  3. Niemutowalność i efekty uboczne
← Powrót do Scala for Backend Engineering & Functional Programming