Przypadek : Pracuję w firmie, pisząc aplikację w języku Python, która obsługuje wiele danych w tablicach. Obecnie jestem jedynym programistą tego programu, ale prawdopodobnie będzie on używany / modyfikowany / rozszerzany w przyszłości (1-3 lata) przez innego programistę, w tej chwili mi nieznanego. Prawdopodobnie nie będę tam bezpośrednio, aby pomóc, ale może udzielę wsparcia przez e-mail, jeśli mam na to czas.
Tak więc, jako programista, który nauczył się programowania funkcjonalnego (Haskell), mam tendencję do rozwiązywania, na przykład, filtrowania w następujący sposób:
filtered = filter(lambda item: included(item.time, dur), measures)
Reszta kodu to OO, to tylko niektóre małe przypadki, w których chcę go rozwiązać w ten sposób, ponieważ według mnie jest znacznie prostszy i piękniejszy.
Pytanie : Czy pisanie takiego kodu dzisiaj jest w porządku?
- Jak programista, który nie napisał / nie nauczył się FP, reaguje na taki kod?
- Czy to jest czytelne?
- Modyfikowalny?
Czy powinienem napisać dokumentację, taką jak wyjaśnienie dziecku, co robi linia?
# Filter out the items from measures for which included(item.time, dur) != True
Zapytałem mojego szefa, a on po prostu powiedział: „FP to czarna magia, ale jeśli działa i jest najbardziej wydajnym rozwiązaniem, to można z niej korzystać”.
Jaka jest twoja opinia na ten temat? Jako programista inny niż FP, jak reagujesz na kod? Czy kod jest „googable”, abyś mógł zrozumieć, co robi? Chciałbym poznać opinie na ten temat.
# Select the item's from measures for which included(item.time, dur) == True
unikanie podwójnego negatywu zawsze poprawia zrozumienie.Odpowiedzi:
Dla mnie: Tak, ale doszedłem do wniosku, że społeczność Python często wydaje się, że rozumienie list jest rozwiązaniem czystszym niż używanie
map()
/filter()
.W rzeczywistości GvR rozważał nawet całkowite usunięcie tych funkcji.
Rozważ to:
Ponadto ma to tę zaletę, że zrozumienie listy zawsze zwraca listę.
map()
afilter()
z drugiej strony zwraca iterator w Pythonie 3.Uwaga: jeśli zamiast tego chcesz mieć iterator, wystarczy zastąpić
[]
go()
:Szczerze mówiąc, niewiele widzę żadnego powodu do stosowania
map()
lubfilter()
w Pythonie.Tak, z pewnością jednak jest jedna rzecz, która to ułatwia: uczyń to funkcją, a nie lambda.
Jeśli twój stan stanie się bardziej złożony, skaluje się on znacznie łatwiej, a także pozwala ponownie użyć czeku. (Pamiętaj, że możesz tworzyć funkcje wewnątrz innych funkcji, dzięki czemu może znajdować się bliżej miejsca, w którym jest używany).
Przegląda dokumentację Pythona i wie, jak to działa pięć minut później. W przeciwnym razie nie powinien programować w języku Python.
map()
ifilter()
są niezwykle proste. To nie tak, że prosisz ich o zrozumienie monad. Dlatego nie sądzę, że musisz pisać takie komentarze. Używaj dobrych nazw zmiennych i funkcji, wtedy kod jest prawie oczywisty. Nie możesz przewidzieć, jakie funkcje językowe nie zna programista. Z tego co wiesz, następny programista może nie wiedzieć, czym jest słownik.To, czego nie rozumiemy, zwykle nie jest dla nas czytelne. Dlatego możesz argumentować, że jest nie mniej czytelny niż zrozumienie listy, jeśli nigdy wcześniej nie widziałeś żadnego z nich. Ale jak wspomniał Joshua w swoim komentarzu, również uważam, że ważne jest, aby zachować spójność z tym, co używają inni programiści - przynajmniej jeśli alternatywa nie zapewnia znaczącej przewagi.
źródło
map
ifilter
zrobić w Pythonie 3.reduce
przykład przeciwny do tego, że zawsze możesz użyć argumentu ze zrozumieniem listy , ponieważ stosunkowo trudno jest zastąpićreduce
go wbudowanym generatorem lub zrozumieniem listy.Ponieważ społeczność programistów odzyskuje zainteresowanie programowaniem funkcjonalnym, nie jest niczym niezwykłym zobaczenie programowania funkcjonalnego w językach, które pierwotnie były w pełni obiektowe. Dobrym przykładem jest C #, w którym typy anonimowe i wyrażenia lambda pozwalają być znacznie krótsze i bardziej ekspresyjne dzięki programowaniu funkcjonalnemu.
To powiedziawszy, programowanie funkcjonalne jest dziwne dla początkujących. Na przykład, kiedy podczas szkolenia wyjaśniłem początkującym, w jaki sposób mogą ulepszyć swój kod poprzez programowanie funkcjonalne w języku C #, niektórzy z nich nie byli przekonani, a niektórzy stwierdzili, że oryginalny kod był dla nich łatwiejszy do zrozumienia. Dałem im przykład:
Kod przed refaktoryzacją:
Ten sam kod po refaktoryzacji przy użyciu FP:
To sprawia, że myślę, że:
nie powinieneś się martwić, jeśli wiesz, że następny programista, który będzie utrzymywał twój kod, będzie miał wystarczającą ogólną wiedzę i trochę wiedzy na temat programowania funkcjonalnego, ale:
w przeciwnym razie unikaj programowania funkcjonalnego lub wstaw swój komentarz wyjaśniający jednocześnie składnię, zalety i możliwe zastrzeżenia twojego podejścia w porównaniu do niefunkcjonalnego programowania.
źródło
Nie jestem programistą FP, a ostatnio miałem zmodyfikować kod mojego kolegi w JavaScript. Pojawiło się żądanie HTTP z oddzwonieniem, które wyglądało bardzo podobnie do dołączonego przez ciebie oświadczenia. Muszę powiedzieć, że zajęło mi to trochę czasu (jak pół godziny), aby to wszystko rozgryźć (w sumie kod nie był zbyt duży).
Nie było komentarzy i myślę, że nie było takiej potrzeby. Nawet nie poprosiłem mojego kolegi o pomoc w zrozumieniu jego kodu.
Biorąc pod uwagę, że pracuję od około 1,5 roku, myślę, że większość programistów będzie w stanie zrozumieć i zmodyfikować taki kod, odkąd to zrobiłem.
Poza tym, jak powiedział Joachim Sauer w swoim komentarzu, często są fragmenty FP w wielu językach, na przykład C # (na przykład indexOf). Tak wielu programistów spoza FP zajmuje się tym dość często, a dołączony fragment kodu nie jest czymś strasznym ani niezrozumiałym.
źródło
Powiedziałbym zdecydowanie tak!
Istnieje wiele aspektów programowania funkcjonalnego, a używanie funkcji wyższego rzędu, jak w twoim przykładzie, jest tylko jednym z nich.
Na przykład uważam, że pisanie czystych funkcji jest niezwykle ważne dla każdego oprogramowania napisanego w dowolnym języku (gdzie przez „czysty” nie mam żadnych skutków ubocznych), ponieważ:
Często też unikam mutowania wartości i zmiennych - kolejna koncepcja zapożyczona z FP.
Obie te techniki działają dobrze w języku Python i innych językach, które zwykle nie są klasyfikowane jako funkcjonalne. Często są nawet obsługiwane przez sam język (tj.
final
Zmienne w Javie). Zatem przyszli programiści zajmujący się konserwacją nie napotkają ogromnej bariery w zrozumieniu kodu.źródło
Tę samą dyskusję przeprowadziliśmy w firmie, w której pracowałem w zeszłym roku.
Dyskusja dotyczyła „magicznego kodu” i tego, czy należy go zachęcać, czy nie. Przyglądając się temu nieco bardziej, wydawało się, że ludzie mieli bardzo różne poglądy na temat tego, co tak naprawdę było „magicznym kodem”. Ci, którzy podjęli dyskusję, zdawali się oznaczać głównie, że wyrażenia (w PHP), które używały stylu funkcjonalnego, były „magicznym kodem”, podczas gdy programiści, którzy wywodzili się z innych języków, którzy używali więcej stylu FP w swoim kodzie, wydają się sądzić, że magiczny kod był raczej kiedy dynamicznie włączasz pliki za pomocą nazw plików i tak dalej.
Nigdy nie doszliśmy do żadnych dobrych wniosków na ten temat, ponadto ludzie w większości uważają, że kod, który wydaje się nieznany, jest „magiczny” lub trudny do odczytania. Czy warto unikać kodu, który nie jest znany innym użytkownikom? Myślę, że to zależy od tego, gdzie jest używane. Powstrzymałbym się od używania wyrażeń w stylu fp (dynamiczne dołączanie plików itp.) W głównej metodzie (lub ważnych centralnych częściach aplikacji), w której dane powinny być tunelowane w jasny i łatwy do odczytania, intuicyjny sposób. Z drugiej strony, nie sądzę, że należy bać się przesunąć kopertę, inni programiści prawdopodobnie szybko nauczą się FP, jeśli napotkają kod FP i mogą mieć jakieś dobre wewnętrzne zasoby do konsultacji w tych kwestiach.
TL; DR: Unikaj w centralnej części aplikacji wysokiego poziomu (które należy przeczytać, aby zapoznać się z przeglądem funkcjonalności aplikacji). W przeciwnym razie użyj go.
źródło
Społeczność C ++ ostatnio otrzymała również lambda i uważam, że mają mniej więcej to samo pytanie. Odpowiedź może jednak nie być taka sama. Odpowiednikiem C ++ byłoby:
Teraz
std::copy
nie jest nowy, a_if
warianty też nie są nowe, ale lambda jest. Jednak jest on zdefiniowany raczej jasno w kontekście:dur
jest przechwytywany, a zatem stały,Item i
zmienia się w pętli, a pojedynczareturn
instrukcja wykonuje całą pracę.To wygląda na akceptowalne dla wielu programistów C ++. Nie próbowałem jednak opinii na temat lambda wyższego rzędu i spodziewałbym się znacznie mniejszej akceptacji.
źródło
Opublikuj fragment kodu do innego programisty, który nie jest tak płynny w Pythonie, i zapytaj go, czy może poświęcić 5 minut na sprawdzenie kodu, aby zobaczyć, czy on rozumie.
Jeśli tak, prawdopodobnie dobrze jest iść. Jeśli nie, powinieneś spojrzeć na to, aby było jaśniej.
Czy twój kolega może być głupi i nie rozumieć czegoś, co powinno być oczywiste? Tak, ale zawsze należy programować zgodnie z KISS.
Może Twój kod jest bardziej wydajny / przystojny / elegancki niż prostsze, idiotyczne podejście? Następnie musisz zadać sobie pytanie: czy muszę to zrobić? Ponownie, jeśli odpowiedź brzmi „nie”, nie rób tego!
Jeśli po tym wszystkim nadal uważasz, że potrzebujesz i chcesz to zrobić FP, to zrób to wszystko. Zaufaj swoim instynktom, są one lepiej dostosowane do twoich potrzeb niż większość ludzi na jakimkolwiek forum :)
źródło