Oto kod, który gdzieś natknąłem, ale chcę wiedzieć, jak to działa:
findIndices :: (a -> Bool) -> [a] -> [Int]
findIndices _ [] = []
findIndices pred xs = map fst (filter (pred . snd) (zip [0..] xs))
Dane wyjściowe: findIndices (== 0) [1,2,0,3,0] == [2,4] , gdzie pred wynosi (== 0), a xs wynosi [1,2,0,3,0]
Pokażę trochę mojego zrozumienia:
(zip [0..] xs)
Powyższa linia wprowadza indeksy do wszystkiego na liście. Dla danych wejściowych podanych powyżej wyglądałoby to tak: [(0,1), (1,2), (2,0), (3,3), (4,0)]
(pred . snd)
Odkryłem, że oznacza to coś w rodzaju pred (snd (x)). Moje pytanie brzmi: czy x jest listą utworzoną z linii zip? Skłaniam się ku tak, ale moje przypuszczenia są wątłe.
Następnie moje rozumienie fst i snd. wiem to
fst(1,2) = 1
i
snd(1,2) = 2
Jak te 2 polecenia mają sens w kodzie?
Rozumiem, że filtr polega na tym, że zwraca listę elementów spełniających warunek. Na przykład,
listBiggerThen5 = filter (>5) [1,2,3,4,5,6,7,8,9,10]
dałby [6,7,8,9,10]
Rozumiem, że mapa ma zastosowanie do każdej pozycji na liście. Na przykład,
times4 :: Int -> Int
times4 x = x * 4
listTimes4 = map times4 [1,2,3,4,5]
dałby [4,8,12,16,20]
Jak to ogólnie działa? Wydaje mi się, że byłem wyczerpujący w tym, co wiem do tej pory, ale nie jestem w stanie poskładać całości. Czy ktokolwiek może mi pomóc?
źródło
Odpowiedzi:
W Haskell lubimy mówić: podążaj za typami . Rzeczywiście elementy łączą się jakby drutami przechodzącymi od typu do odpowiedniego typu:
(po pierwsze, skład funkcji to:
a regułą wnioskowania o składzie funkcji jest
Teraz, )
więc ogólnie
Zapytałeś, jak te elementy pasują do siebie?
Oto jak.
Z listami twoja funkcja jest zapisana jako
który w pseudokodzie brzmi:
„lista zawiera wynik
i
dla siebie(i,x)
wzip [0..] xs
taki sposób, żepred x
posiada” .Robi to, obracając
n
-długiew
gdzie
[a | True]
jest[a]
i[a | False]
jest[]
.źródło
Cóż
pred . snd
, znaczy\x -> pred (snd x)
. Więc to w zasadzie tworzy funkcję, która mapuje elementx
napred (snd x)
.Oznacza to zatem, że wyrażenie wygląda następująco:
Oto
x
2-krotność wygenerowana przezzip
. Tak, aby wiedzieć, czy(0, 1)
,(1,2)
,(2, 0)
, itd. Są zatrzymywane w wynikusnd x
weźmie drugi element tych 2-krotek (tak1
,2
,0
, itd), i sprawdzić, czypred
na tha elementu jest usatysfakcjonowany lub nie. Jeśli jest spełniony, zachowuje element, w przeciwnym razie element (2-krotka) zostanie odfiltrowany.Więc jeśli
(== 0)
jestpred
icate, tofilter (pred . snd) (zip [0..] xs)
będzie zawierać 2-krotki[(2, 0), (4, 0)]
.Ale teraz wynikiem jest lista 2-krotek. Jeśli chcemy indeksów, musimy jakoś pozbyć się 2-krotek i drugiego elementu tych 2-krotek. Używamy
fst :: (a, b) -> a
do tego: to mapuje 2-krotkę na pierwszym elemencie. Tak na listy[(2, 0), (4, 0)]
,map fst [(2, 0), (4, 0)]
powróci[2, 4]
.źródło