Scala Language
Funkcja wyższego rzędu
Szukaj…
Uwagi
Scala dokłada wszelkich starań, aby traktować metody i funkcje jako identyczne pod względem składniowym. Ale pod maską są to odrębne koncepcje.
Metoda jest kodem wykonywalnym i nie ma reprezentacji wartości.
Funkcja jest faktyczną instancją obiektu typu Function1
(lub podobnego rodzaju innej arity). Jego kod jest zawarty w metodzie apply
. Skutecznie działa po prostu jako wartość, którą można przekazać.
Nawiasem mówiąc, zdolność do traktowania funkcji jako wartości jest dokładnie tym, co rozumie się przez język obsługujący funkcje wyższego rzędu. Instancje funkcji są podejściem Scali do implementacji tej funkcji.
Rzeczywista funkcja wyższego rzędu to funkcja, która albo przyjmuje wartość funkcji jako argument, albo zwraca wartość funkcji. Ale w Scali, ponieważ wszystkie operacje są metodami, ogólniej jest myśleć o metodach, które odbierają lub zwracają parametry funkcji. Tak więc map
zdefiniowana w Seq
może być uważana za „funkcję wyższego rzędu”, ponieważ jej parametr jest funkcją, ale nie jest dosłownie funkcją; to jest metoda.
Wykorzystanie metod jako wartości funkcji
Kompilator Scala automatycznie konwertuje metody na wartości funkcji w celu przekazania ich do funkcji wyższego rzędu.
object MyObject {
def mapMethod(input: Int): String = {
int.toString
}
}
Seq(1, 2, 3).map(MyObject.mapMethod) // Seq("1", "2", "3")
W powyższym przykładzie MyObject.mapMethod
nie jest wywołaniem funkcji, ale zamiast tego jest przekazywany do map
jako wartość. Rzeczywiście, map
wymaga przekazania wartości funkcji, co można zobaczyć w jej sygnaturze. Podpis map
List[A]
(listy obiektów typu A
) to:
def map[B](f: (A) ⇒ B): List[B]
Część f: (A) => B
wskazuje, że parametrem tego wywołania metody jest jakaś funkcja, która pobiera obiekt typu A
i zwraca obiekt typu B
A
i B
są arbitralnie zdefiniowane. Wracając do pierwszego przykładu, możemy zobaczyć, że mapMethod
przyjmuje Int
(co odpowiada A
) i zwraca String
(który odpowiada B
). Zatem mapMethod
jest prawidłową wartością funkcji, którą należy przekazać do map
. Możemy przepisać ten sam kod w ten sposób:
Seq(1, 2, 3).map(x:Int => int.toString)
Podkreśla to wartość funkcji, która może zwiększyć przejrzystość prostych funkcji.
Funkcje wyższego rzędu (funkcja jako parametr)
Funkcja wyższego rzędu, w przeciwieństwie do funkcji pierwszego rzędu, może mieć jedną z trzech postaci:
Co najmniej jeden z jego parametrów jest funkcją i zwraca pewną wartość.
Zwraca funkcję, ale żaden z jej parametrów nie jest funkcją.
Oba powyższe: jeden lub więcej jego parametrów jest funkcją i zwraca funkcję.
object HOF { def main(args: Array[String]) { val list = List(("Srini","E"),("Subash","R"),("Ranjith","RK"),("Vicky","s"),("Sudhar","s")) //HOF val fullNameList= list.map(n => getFullName(n._1, n._2)) } def getFullName(firstName: String, lastName: String): String = firstName + "." + lastName }
Tutaj funkcja mapy przyjmuje jako parametr parametr getFullName(n._1,n._2)
. Nazywa się to HOF (funkcja wyższego rzędu).
Argumenty leniwe oceny
Scala obsługuje leniwe ocenianie argumentów funkcji za pomocą notacji: def func(arg: => String)
. Taki argument funkcji może przyjmować zwykły obiekt String
lub funkcję wyższego rzędu z typem zwracanym String
. W drugim przypadku argument funkcji byłby oceniany przy dostępie do wartości.
Zobacz przykład:
def calculateData: String = {
print("Calculating expensive data! ")
"some expensive data"
}
def dumbMediator(preconditions: Boolean, data: String): Option[String] = {
print("Applying mediator")
preconditions match {
case true => Some(data)
case false => None
}
}
def smartMediator(preconditions: Boolean, data: => String): Option[String] = {
print("Applying mediator")
preconditions match {
case true => Some(data)
case false => None
}
}
smartMediator(preconditions = false, calculateData)
dumbMediator(preconditions = false, calculateData)
smartMediator
zwróci Brak wartości i wyświetli komunikat "Applying mediator"
.
dumbMediator
zwróci Brak wartości i wyświetli komunikat "Calculating expensive data! Applying mediator"
.
Leniwa ocena może być bardzo przydatna, gdy chcesz zoptymalizować kosztowne obliczenia kosztownych argumentów.