Nauczyłem się podstawowej różnicy między foldLeft
ireduceLeft
foldLeft:
- wartość początkowa musi zostać przekazana
zmniejszLeft:
- przyjmuje pierwszy element kolekcji jako wartość początkową
- zgłasza wyjątek, jeśli kolekcja jest pusta
Czy jest jakaś inna różnica?
Czy jest jakiś konkretny powód, aby mieć dwie metody o podobnej funkcjonalności?
scala
functional-programming
fold
higher-order-functions
Rajesh Pitty
źródło
źródło
Odpowiedzi:
Kilka rzeczy, o których warto tu wspomnieć, zanim podamy właściwą odpowiedź:
left
, dotyczy raczej różnicy między zmniejszaniem a składaniemPowrót do pytania:
Oto podpis
foldLeft
(mógłbym również zrobićfoldRight
punkt, który zamierzam zrobić):A oto podpis
reduceLeft
(znowu kierunek nie ma tutaj znaczenia)Te dwa wyglądają bardzo podobnie, powodując zamieszanie.
reduceLeft
jest szczególnym przypadkiemfoldLeft
(co przy okazji oznacza, że czasami możesz wyrazić to samo, używając jednego z nich).Kiedy wywołasz
reduceLeft
say na aList[Int]
, dosłownie zredukuje całą listę liczb całkowitych do pojedynczej wartości, która będzie typuInt
(lubInt
odtąd typu[B >: A]
).Kiedy wywołasz
foldLeft
say na aList[Int]
, zwinie całą listę (wyobraź sobie zwinięcie kartki papieru) w jedną wartość, ale ta wartość nie musi być nawet związanaInt
(stąd[B]
).Oto przykład:
Ta metoda pobiera a
List[Int]
i zwraca aTuple2[List[Int], Int]
lub(List[Int], Int)
. Oblicza sumę i zwraca krotkę z listą liczb całkowitych i jej sumy. Nawiasem mówiąc, lista jest zwracana wstecz, ponieważ użyliśmyfoldLeft
zamiastfoldRight
.Obejrzyj One Fold, aby rządzić nimi wszystkimi, by uzyskać bardziej szczegółowe wyjaśnienia.
źródło
B
jest to nadtypA
? Wydaje się, żeB
powinien to być podtypA
, a nie nadtyp. Na przykład, zakładającBanana <: Fruit <: Food
, że gdybyśmy mieli listęFruit
s, wydaje się, że może ona zawierać niektóreBanana
s, ale jeśli zawiera jakieśFood
s, to typ byłbyFood
, prawda? Więc w tym przypadku, jeśliB
jest nadtypA
i istnieje lista zawierająca zarównoB
s, jak iA
s, lista powinna być typuB
, a nieA
. Czy możesz wyjaśnić tę rozbieżność?List[Banana]
można zredukować liczbę do jednego,Banana
jednegoFruit
lub jednegoFood
. PonieważFruit :> Banana
i „Jedzenie:> Banan”.Banana
może zawieraćFruit
”, co nie ma sensu. Twoje wyjaśnienie ma sens - przekazanaf
funkcjareduce()
może dać aFruit
lub aFood
, co oznacza,B
że podpis powinien być nadklasą, a nie podklasą.reduceLeft
to tylko wygodna metoda. Jest to równoważne zźródło
reducelft
choćfold
działa na pustej liście, areduce
nie działa.foldLeft
jest bardziej ogólny, możesz go użyć do stworzenia czegoś zupełnie innego niż to, co pierwotnie umieściłeś. Podczas gdyreduceLeft
może dać tylko wynik końcowy tego samego typu lub supertypu typu kolekcji. Na przykład:foldLeft
Zastosuje zamknięcia z ostatniego złożonego wyniku (pierwszy raz przy użyciu wartości początkowej) oraz kolejną wartość.reduceLeft
z drugiej strony najpierw połączą dwie wartości z listy i zastosują je do zamknięcia. Następnie połączy pozostałe wartości z łącznym wynikiem. Widzieć:Jeśli lista jest pusta,
foldLeft
może przedstawić wartość początkową jako wynik prawny.reduceLeft
z drugiej strony nie ma wartości prawnej, jeśli nie może znaleźć co najmniej jednej wartości na liście.źródło
Podstawowym powodem, dla którego oba znajdują się w standardowej bibliotece Scala, jest prawdopodobnie dlatego, że oba znajdują się w standardowej bibliotece Haskell (nazywanej
foldl
ifoldl1
). JeślireduceLeft
nie, to często jest definiowany jako metoda wygodna w różnych projektach.źródło
W celach informacyjnych
reduceLeft
wystąpi błąd, jeśli zostanie zastosowany do pustego pojemnika z następującym błędem.Przerób kod do użycia
jest jedną z potencjalnych opcji. Innym jest użycie
reduceLeftOption
wariantu, który zwraca wynik zawarty w Opcji.źródło
Z zasad programowania funkcjonalnego w Scali (Martin Odersky):
[w przeciwieństwie do
reduceLeft
, który zgłasza wyjątek, gdy jest wywoływany na pustej liście.]Kurs (patrz wykład 5.5) zawiera abstrakcyjne definicje tych funkcji, które ilustrują ich różnice, chociaż są one bardzo podobne w stosowaniu dopasowywania wzorców i rekurencji.
Zauważ, że
foldLeft
zwraca wartość typuU
, która niekoniecznie jest tego samego typuList[T]
, ale redukcja zwraca wartość tego samego typu co lista).źródło
Aby naprawdę zrozumieć, co robisz ze składaniem / zmniejszaniem, sprawdź to: http://wiki.tcl.tk/17983 bardzo dobre wyjaśnienie. gdy pojawi się koncepcja składania, redukcja pojawi się wraz z odpowiedzią powyżej: list.tail.foldLeft (list.head) (_)
źródło