Próbuję zrozumieć część w uwagach do wykładu z zajęć, które biorę. Definiuje funkcję długości jako:Definicja długości za pomocą foldr
length = foldr (\_ n -> 1 + n) 0
Czy ktoś może mi wyjaśnić, jak to działa? Nie mogę otoczyć się tym.
Próbuję zrozumieć część w uwagach do wykładu z zajęć, które biorę. Definiuje funkcję długości jako:Definicja długości za pomocą foldr
length = foldr (\_ n -> 1 + n) 0
Czy ktoś może mi wyjaśnić, jak to działa? Nie mogę otoczyć się tym.
Najpierw, z foldr
: (a -> b -> b) -> b -> [a] -> b
Biorąc użycia w kontekście, foldr
pobiera 3 argumenty funkcji (które pobiera element listy i b akumulator,.. i zwraca akumulator), wartość początkową akumulatora i listę. foldr
zwraca końcowy wynik akumulatora po zastosowaniu funkcji na liście.
chodzi o ten kawałek kodu:
length = foldr (\_ n -> 1 + n) 0
Jak widać, to brakuje na liście - tak wartość zwracaną po prawej stronie to funkcja, która odbędzie się na liście i produkują Int (ten sam typ co 0
). Wpisz: [a] -> Int
.
chodzi o to, co prawej stronie oznacza: (\_ n -> 1 + n) 0
\
środki zadeklarować nienazwany funkcję
_
środki ignorować elementu z listy (odpowiadają a
w rodzaju foldr
). Jak wiesz, foldr
przejdzie przez listę i zastosuje funkcję do każdego elementu. Jest to element przekazany do funkcji. Nie używamy go w funkcji length
, więc oznaczamy, że należy go zignorować.
n
to parametr dla przekazywanego przez Int jako akumulator.
->
środki powrotne
1 + n
będzie zwiększać akumulatora. Można sobie wyobrazić, że zwracana wartość jest przekazywana z powrotem do foldr
i foldr
zapisuje wartość, aby przejść do następnego połączenia z funkcją (\_ n -> 1 + n)
.
Wartość 0
poza nawiasem jest wartością początkową licznika.
Tylko uwaga : Haskell nie jest moim językiem - dowiedziałem się o tym i zrozumiałem, jak to działa, ale nie koduję zbyt wiele z Haskellem. Jeśli wystąpi jakikolwiek błąd - uprzejmie prosimy o zwrócenie uwagi. – nhahtdh
Dziękuję za wyjaśnienie. – hattenn
@nhahtdh - dobre wyjaśnienie, ale typem prawej strony byłoby "[a] -> Integer"; ponieważ 'foldr' stosuje się do dwóch argumentów, możesz po prostu upuścić dwa pierwsze argumenty z jego typu, a ostateczny typ to, co zostało (po unifikacji typu). Z wyjątkiem, ponieważ literały liczbowe są polimorficzne, typ wyniku nie jest w rzeczywistości typu "Integer", ale jest polimorficzny, więc 'Num b => [a] -> b'. –
Funkcja foldr
jest rozkładana na liście z prawej operatora asocjacyjnej, można łatwo zrozumieć, co funkcja robi, jeśli użyć operatora (+)
(Funkcja ma takie samo zachowanie jak sum
):
foldr (+) 0 [1,2,3,4,5] = 1+(2+(3+(4+(5+0))))
dla funkcji długości, jest równoznaczne z:
foldr (\_ n -> 1 + n) 0 [1,2,3,4,5] = 1+(1+(1+(1+(1+0))))
to właśnie foldr
dla
Istnieje kilka równoważnych sposobów, aby to zrozumieć.Pierwszy z nich: foldr f z [1, 2, 3, 4, ..., n]
oblicza następującą wartość:
f 1 (f 2 (f 3 (f 4 (f ... (f n z)))))
Więc w twoim przypadku:
length [1,2,3,4] = foldr (\_ n -> 1 + n) 0 [1,2,3,4]
= (\_ n -> 1 + n) 1 ((\_ n -> 1 + n) 2 ((\_ n -> 1 + n) 3 ((\_ n -> 1 + n) 4 0)))
= (\_ n -> 1 + n) 1 ((\_ n -> 1 + n) 2 ((\_ n -> 1 + n) 3 (1 + 0)))
= (\_ n -> 1 + n) 1 ((\_ n -> 1 + n) 2 (1 + (1 + 0)))
= (\_ n -> 1 + n) 1 (1 + (1 + (1 + 0)))
= 1 + (1 + (1 + (1 + 0)))
= 1 + (1 + (1 + 1))
= 1 + (1 + 2)
= 1 + 3
= 4
Kolejnym jest zacząć od tej funkcji, która kopiuje listę:
listCopy :: [a] -> [a]
listCopy [] = []
listCopy (x:xs) = x : listCopy xs
Że może wyglądać jak trywialna funkcja, ale foldr
jest po prostu tym, ale z wyjątkiem kodowania na pustej liście []
i konstruktora par :
po prawej stronie, zamiast tego używamy pewnej arbitralnej stałej i funkcji dostarczonej jako argumenty. Ja czasami lubię nazywać te argumenty fakeCons
i fakeNil
(cons
i nil
są nazwy operatora :
i []
stała w języku Lisp), ponieważ w pewnym sensie jesteś „kopiowanie” lista, ale przy użyciu fałszywych konstruktorów:
foldr fakeCons fakeNil [] = fakeNil
foldr fakeCons fakeNil (x:xs) = fakeCons x (subfold xs)
where subfold = foldr fakeCons fakeNil
Więc pod tą interpretacją, czynność length
to „kopiowanie” lista, z wyjątkiem, że zamiast pustej liście jest za pomocą 0
i zamiast :
to odrzucając elementy i dodając 1 do uruchomionej sumie.
A oto jeszcze jedna trzecia intepretation z foldr f z xs
:
z
jest rozwiązaniem problemu, gdy lista jest pusta.f
to funkcja, która przyjmuje dwa argumenty: element listy, a częściowe rozwiązanie: rozwiązanie problemu na liście elementów, które pojawiają się po prawej stronie elementu, który jest przekazywany do f
. f
następnie tworzy rozwiązanie, które jest "jeden element większy".Tak więc w przypadku length
:
foldr
.xs
to n
, to długość x:xs
to n+1
. Oto, co robi twój pierwszy argument na foldr
, \_ n -> n + 1
: oblicza długość listy, podając jako argumenty pierwszy element listy (który w tym przypadku ignorujemy) i długość reszty listy (n
) .Ten sposób myślenia o foldr
jest bardzo potężny i nie należy go lekceważyć. Zasadniczo w funkcji, którą przekazujesz jako pierwszy argument do foldr
, możesz założyć, że problem, który próbujesz rozwiązać, został już rozwiązany dla wszystkich list krótszych niż ten, z którym masz do czynienia. Trzeba zatem wykonać całą swoją funkcję argumentu, aby obliczyć odpowiedź dla listy, która jest dłuższa o jeden element.
patrz http://stackoverflow.com/questions/7704960/how-to-write-a- length-function-using-foldr-in-haskell na początek. –
Zobacz także: http: // learnyouahaskell.com/higher-order-functions # folds –
Byłoby lepiej, gdybyś użył 'foldl'', który jest dobry dla twojego stosu ' length = foldl '(\ n _ -> n + 1) 0' – Ronson