C # , Scala, Haskell, Lisp i Pythonzip
zachowują się tak samo : jeśli jedna kolekcja jest dłuższa, ogon jest cicho ignorowany.
Może to być również wyjątek, ale nie słyszałem o żadnym języku używającym takiego podejścia.
To mnie zastanawia. Czy ktoś wie, dlaczego zip
jest tak zaprojektowany? Sądzę, że w przypadku nowych języków jest to zrobione, ponieważ inne języki robią to w ten sposób. Ale jaki był główny powód?
Zadaję tu oparte na faktach, historyczne pytanie, nie jeśli komuś się to podoba, czy jest to dobre czy złe podejście.
Aktualizacja : Gdybym został zapytany, co robić, powiedziałbym - rzuć wyjątek, podobnie jak indeksowanie tablicy (pomimo, że „stare” języki robiły wszelkiego rodzaju magię, jak radzić sobie z indeksem poza granicami, UB, rozszerzanie tablicy, itp).
źródło
zipWithIndex
generując liczby naturalne. Teraz jedyny brakujący fragment informacji - jaki był tego powód? :-) (btw. proszę ponownie opublikować swój komentarz jako odpowiedź, dziękuję).Odpowiedzi:
Prawie zawsze jest to, czego chcesz, a kiedy nie jest, możesz zrobić to sam.
Główny problem dotyczy leniwej semantyki, której nie znasz długości przy pierwszym uruchomieniu
zip
, więc nie możesz po prostu rzucić wyjątku na początku. Musisz najpierw zwrócić wszystkie wspólne elementy, a następnie zgłosić wyjątek, który nie byłby bardzo przydatny.To także kwestia stylu. Niezwykle programiści są przyzwyczajeni do ręcznego sprawdzania warunków brzegowych w dowolnym miejscu. Funkcjonalni programiści preferują konstrukcje, które nie mogą zawieść z założenia. Wyjątki są niezwykle rzadkie. Jeśli istnieje sposób na zwrócenie rozsądnej wartości domyślnej przez funkcję, programiści funkcjonalni ją przyjmą. Kompozycja jest królem.
źródło
zip
jest obecnie wdrażany. Wyjątkiem od rzucania jest po prostu zmiana „stop fed” na „throw”. Trzeci akapit - zwracanie pustego elementu do przekroczenia granicy nie może zawieść, ale wątpię, aby którykolwiek programista FP głosowałby, że to dobry projekt.zip
dwie nieskończone sekwencje razem, nie znacie rozmiaru na początku. W trzecim akapicie powiedziałem, że jest to uzasadnione naruszenie. Zwrócenie pustego w tym przypadku nie byłoby rozsądne, podczas gdy oczywiście upuszczenie ogona.Ponieważ nie ma oczywistego sposobu na ukończenie ogona. Jakikolwiek wybór, jak to zrobić, spowodowałoby nieoczywisty ogon.
Sztuką jest wyraźne wydłużenie najkrótszej listy, aby dopasować długość najdłuższej do oczekiwanych wartości.
Jeśli zip zrobił to za Ciebie, nie mogłeś wiedzieć, jakie wartości wypełniał intuicyjnie. Czy przeglądał listę? Czy to powtórzyło wartość pustą? Jaka jest wartość pusta dla twojego typu?
Nie ma żadnego wpływu na to, co robi zip, którego można by użyć do intuicyjnego sposobu wydłużania ogona, więc jedyną rozsądną rzeczą do zrobienia jest praca z dostępnymi wartościami, a nie wymyślanie czegoś, czego konsument może się nie spodziewać.
Pamiętaj też, że masz na myśli bardzo konkretną dobrze znaną funkcję z określoną dobrze znaną semantyką. Ale to nie znaczy, że nie możesz wykonać podobnej, ale nieco innej funkcji . Tylko dlatego, że jest to wspólna funkcja robi
x
, nie znaczy, że nie może decydować za dany cel, który chcesz zrobićx
ay
.Pamiętaj jednak, że ta i wiele innych powszechnych funkcji w stylu FP są wspólne, ponieważ są one proste i uogólnione, dzięki czemu możesz dostosować kod, aby z nich korzystać i uzyskać pożądane zachowanie. Na przykład w języku C # można po prostu
Lub inne proste rzeczy. Podejścia FP sprawiają, że modyfikacje są tak łatwe, ponieważ można ponownie wykorzystywać elementy, a także mieć tak małe implementacje, że tworzenie własnych zmodyfikowanych wersji rzeczy jest niezwykle proste.
źródło
zip
może wypełnić wartości zerowe, co jest często intuicyjnym rozwiązaniem. Rozważ typzip :: [a] -> [b] -> [(Maybe a, Maybe b)]
. To prawda, że typ wyniku jest nieco ^ H ^ H dość niepraktyczny, ale pozwoliłby łatwo zaimplementować na nim jakiekolwiek inne zachowanie (skrót, wyjątek).mempty
, że obiekty mają wartość null, aby wypełnić przestrzeń, ale chcesz, aby wymyśliła coś takiego dla int i innych typów? Jasne, C # ma,default(T)
ale nie wszystkie języki, a nawet dla C # czy to naprawdę oczywiste zachowanie? Nie sądzę