Pytanie Dwa sposoby definiowania funkcji w Scali. Jaka jest różnica?


Oto mała sesja Scala, która definiuje i wypróbowuje niektóre funkcje:

scala> def test1(str: String) = str + str;    
test1: (str: String)java.lang.String

scala> test1("ab")
res0: java.lang.String = abab

działa ładnie.

scala> val test2 = test1
<console>:6: error: missing arguments for method test1 in object $iw;
follow this method with `_' if you want to treat it as a partially applied function
       val test2 = test1
                   ^

oops.

scala> val test2 = test1 _
test2: (String) => java.lang.String = <function1>

scala> test2("ab")
res1: java.lang.String = abab

działa dobrze!

Teraz widziałem _ składnia podczas składania (_ + _itp.). Tak jak ja to rozumiem _ zasadniczo oznacza "argument". Więc test1 _ zasadniczo oznacza funkcję z argumentem, który jest podany test1Ale dlaczego tak nie jest dokładnie tak samo jak po prostu test1? Dlaczego istnieje różnica, jeśli dołączę a _?

Więc wciąż odkrywałem ...

scala> val test3 = (str: String) => str + str
test3: (String) => java.lang.String = <function1>

scala> test3("ab")
res2: java.lang.String = abab

scala> val test4 = test3
test4: (String) => java.lang.String = <function1>

Tutaj działa bez _! Jaka jest różnica między deffunkcja ed, a valfunkcja ed?


44
2018-02-15 20:57


pochodzenie


Rex, oszczędzę ci trochę czasu. Już odpowiedziałeś na to na liście mailingowej w dniu 1/27/2010. To była dobra odpowiedź, więc dodałem do niej zakładki. scala-programming-language.1934581.n4.nabble.com/... - Bradford
@Bradford - Heh, dzięki :) - Rex Kerr
Myślę, że istnieje pewne niefortunne zamieszanie dotyczące użycia terminu "funkcja" / "definiowanie funkcji" w Scali. Parzysty Programowanie w Scali mówi że def definiuje funkcję, ale to nie do końca prawda w zależności od definicji "funkcji". To znaczy. metoda zwraca wynik, który jest a funkcja z jego parametry, ale metoda nie jest wartość funkcji lub obiekt funkcji. Przydałoby się prawdopodobnie rozróżnić te dwa zastosowania terminu "funkcja". - Knut Arne Vedaa
Przeczytaj odpowiedź retronimów w moim podobnym pytaniu z kwietnia '10. stackoverflow.com/questions/2720486/... - (ps, I QRd twój awatar, bardzo zabawny!) - Synesso
W skrócie - funkcja vs. metoda - Maxim


Odpowiedzi:


Nie ma różnicy między funkcją def'ed a funkcją val'ed:

scala> def test1 = (str: String) => str + str
test1: (String) => java.lang.String

scala> val test2 = test1
test2: (String) => java.lang.String = <function1>

scala> val test3 = (str: String) => str + str
test3: (String) => java.lang.String = <function1>

scala> val test4 = test2
test4: (String) => java.lang.String = <function1>

Widzieć? Wszystkie te funkcje są funkcjami wskazanymi przez X => Y typ, jaki mają.

scala> def test5(str: String) = str + str
test5: (str: String)java.lang.String

Czy widzisz X => Y rodzaj? Jeśli tak, idź do okulisty, ponieważ go nie ma. Typ tutaj jest (X)Y, powszechnie używane do oznaczenia metoda.

Tak właściwie, test1, test2, test3 i test4 są wszystkie metody, które zwracają funkcje. test5 to metoda, która zwraca java.lang.String. Również, test1 przez test4 nie przyjmuj parametrów (tylko test1 może i tak), podczas gdy test5 robi.

Różnica jest bardzo prosta. W pierwszym przypadku próbowałeś przypisać metodę do wartości val, ale nie wypełniałeś parametrów, jakie przyjmuje metoda. Tak więc nie udało się, dopóki nie dodałeś dodatkowego podkreślenia, co oznaczało przekształć moją metodę w funkcję.

W drugim przykładzie masz funkcję, więc nie musisz robić nic więcej.

Metoda nie jest funkcją i odwrotnie. Funkcja jest obiektem jednego z nich FunctionN klasy. Metoda jest uchwytem do jakiegoś fragmentu kodu powiązanego z obiektem.

Zobacz różne pytania dotyczące metod i funkcji na przepełnieniu stosu.


53
2018-02-16 01:03



Jest (X)Y typ? Aha, i dzięki za nowe słowo. - Synesso
Uwielbiam tę odpowiedź. Kilka pytań uzupełniających: 1)  Czy widzisz typ X => Y? Co powiesz na drugą linię? Czy nie jest X => Y ponieważ to ma ( i ) na około String? (W przeciwnym razie musiałbym szukać oftamologa na żółtych stronach.) 2) Z twojego opisu wydaje mi się, że funkcje są bardziej ogólne niż metody, i że mogę użyć twojego test1-notacja zamiast test5-notacja wszędzie? Jaka byłaby wada? - aioobe
@Synesso Tak, nie, rodzaj. Jest to reprezentacja REPL hipotetycznego typu metody. - Daniel C. Sobral
@Aioobe Druga linia nie jest X => Y ponieważ nie ma =>. Funkcje są wolniejsze niż metody i nie mogą odbierać parametrów typu - zostało to omówione gdzie indziej w Stack Overflow. - Daniel C. Sobral
scala> val test4 = test2   czy to jest wolontariusz, czy miałeś na myśli Val test4 = test3? - DenisFLASH


The def deklaruje metodę wewnątrz otaczającego obiektu / klasy / cechy, podobnie do sposobu definiowania metod w Javie. Możesz używać tylko defs w obrębie innych obiektów / klas / cech. W REPL nie można zobaczyć otaczającego obiektu, ponieważ jest on "ukryty", ale istnieje.

Nie możesz przypisać def do wartości, ponieważ def nie jest wartością - jest metodą w obiekcie.

The (x: T) => x * x deklaruje i tworzy instancję a obiekt funkcji, który istnieje w czasie wykonywania. Obiektami funkcyjnymi są instancje rozszerzonych klas anonimowych FunctionN cechy. FunctionN cechy pochodzą z apply metoda. Imię apply jest wyjątkowy, ponieważ można go pominąć. Wyrażenie f(x) zostaje zanurzony w f.apply(x).

Linia dolna to - ponieważ obiekty funkcji są wartościami wykonawczymi istniejącymi na stercie, można przypisać je do wartości, zmiennych i parametrów lub zwrócić je z metod jako wartości zwracanych.

Aby rozwiązać problem przypisywania metod do wartości (co może być przydatne), Scala umożliwia użycie znaku zastępczego do utworzenia obiektu funkcji z metody. Wyrażenie test1 _w powyższym przykładzie faktycznie tworzy funkcję otoki wokół metody test1 - jest to odpowiednik x => test1(x).


58
2018-02-15 21:13



Prosta, ale czysta odpowiedź, +1 - Muhammad Hewedy


Podkreślenie oznacza różne rzeczy w różnych kontekstach. Ale zawsze można o tym myśleć rzecz, która się tutaj pojawi, ale nie musi być nazwana.

Po zastosowaniu zamiast parametrów, efektem jest podniesienie metody do funkcji.

scala> def test1(str: String) = str + str; 
test1: (str: String)java.lang.String

scala> val f1 = test1 _
f1: (String) => java.lang.String = <function1>

Uwaga: metoda stała się funkcją typu (String) => String.

Rozróżnienie między metodą a funkcją w Scali polega na tym, że metody są podobne do tradycyjnych metod Java. Nie możesz ich przekazać jako wartości. Jednak funkcje same w sobie są wartościami i mogą być używane jako parametry wejściowe i wartości zwracane.

Podnoszenie może iść dalej:

scala> val f2 = f1 _
f2: () => (String) => java.lang.String = <function0>

Podniesienie tej funkcji powoduje inną funkcję. Ten czas typu () => (ciąg) => (ciąg)

Z tego, co wiem, ta składnia jest równoważna zastępowaniu wszystkich parametrów jawnym podkreśleniem. Na przykład:

scala> def add(i: Int, j: Int) = i + j
add: (i: Int,j: Int)Int

scala> val addF = add(_, _)
addF: (Int, Int) => Int = <function2>

scala> val addF2 = add _    
addF2: (Int, Int) => Int = <function2>

11
2018-02-15 23:00