Dlaczego programowanie imperatywne jest lepsze od programowania funkcjonalnego? [Zamknięte]

13

Tło: Jestem zwolennikiem programowania funkcjonalnego, który pracuje w sklepie VB.NET, w którym dominującym modelem mentalnym jest programowanie imperatywne. Jako że podstawą naszego systemu są WinForms, rozumiem, że nie odejdziemy całkowicie od programowania imperatywnego, ale mimo to staram się używać FP (głównie przez Linq) tam, gdzie to możliwe, ponieważ wierzę w jego zalety.

Argumenty i kontrargumenty przeciwko FP

  1. Można zauważyć, że płynny Linq jest mniej wydajny niż jego imperatywny odpowiednik, ponieważ ten styl przetwarza sekwencję do innej sekwencji i powtarza ją. Ogólnie rzecz biorąc, zajmie to kilka więcej przejść niż podejście imperatywne, które można lepiej zoptymalizować, aby uniknąć powtarzania przejść w sekwencji. Z tego powodu lead nie mógł zrozumieć, dlaczego wybrałbym funkcjonalne podejście, które jest wyraźnie „mniej wydajne”.

    • Kontrargument : argumentowałem, że chociaż czasami jest mniej wydajny pod względem cykli procesora, czułem, że jest on bardziej zrozumiały dla człowieka i łatwiejszy do naśladowania, ponieważ każda linia wykonuje tylko jedną rzecz w ciągu sekwencji. Dla mnie jest to jak linia montażowa, na której każda osoba na jego stanowisku ma tylko jedno zadanie do wykonania. Uważam, że znikomy kompromis wydajności jest rekompensowany przez kod, którego obawy są starannie rozdzielone.
  2. Kolejnym argumentem przeciwko FP, który słyszę w moim sklepie, jest to, że trudniej jest debugować - co jest prawdą. Nie jest łatwo ominąć kod Linq. Czasami muszę rozwikłać łańcuch metod, aby lepiej śledzić i analizować problemy, których nie jestem w stanie natychmiast zauważyć.

    • _Kontr-argument: W większości przypadków nie mam z tym problemu, ponieważ uważam, że styl funkcjonalny jest bardziej deklaratywny w sposobie, w jaki czyta się, a gdy błąd zostanie zgłoszony w łańcuchu funkcjonalnym, zazwyczaj mogę natychmiast wykryć problem.

Moje pytanie

Staram się promować funkcjonalny styl w naszym sklepie i nie wydaje mi się, żebym robił postępy. Robiłem oba style programowania i dopiero niedawno zajmowałem się Haskellem. Pomimo wieloletniego doświadczenia, teraz, gdy rutynowo używam FP w JavaScript, to go rozwinąłem. Uderza nutą słuszności w moim rdzeniu, gdy porównuję ją do tego, co mógłbym zrobić, gdybym trzymał się trybu rozkazującego. Przekwalifikowałem swój mózg w kierunku funkcjonalnego myślenia, w kierunku funkcjonalnej kompozycji.

Nie mogę zrozumieć, jak trudno było przekonać innych o zaletach FP.

Na przykład programiści w moim sklepie używają Linq, ale myślę, że generalnie używają go w kontekście przetwarzania danych domeny. Używam go w bardziej ogólnym znaczeniu i wolę go za każdym razem, gdy mam do czynienia z sekwencjami / listami lub trwałymi strukturami danych. Nie byłem w stanie przekonać moich kolegów z drużyny do rozszerzenia ich użycia Linq.

Próbuję zrozumieć, co powoduje, że programista nie lubi FP.

Chciałbym zobaczyć odpowiedź kogoś, kto ma duże doświadczenie z FP, ale zdecydował się na imperatywny styl. Co skłoniło decyzję do pozostania w trybie rozkazującym zamiast używania funkcjonalności?


Oto dodatkowy przykład podkreślający różnice między programowaniem imperatywnym a funkcjonalnym.

SelectedRowsMetodę naszej siatki napisałem w Linq jako taką:

Public Property SelectedRows() As DataRow() Implements IDataSourceControl.SelectedRows
    Get
        Return Me.ugrBase.Selected.Rows.
            OfType(Of Infragistics.Win.UltraWinGrid.UltraGridRow)().
            Select(Function(ugr) ugr.ListObject).
            OfType(Of DataRowView)().
            Select(Function(drv) drv.Row).
            ToArray
    End Get

Jednak ten styl kodu sprawia, że ​​niektórzy nasi programiści czują się niekomfortowo, więc nasz przewodnik przepisał go na bardziej znany:

Public Property SelectedRows() As DataRow() Implements IDataSourceControl.SelectedRows
    Get
        Dim plstRows As New List(Of DataRow)
        For Each bugrLoop As Infragistics.Win.UltraWinGrid.UltraGridRow In Me.ugrBase.Selected.Rows
            If bugrLoop.ListObject IsNot Nothing Then
                plstRows.Add(CType(bugrLoop.ListObject, DataRowView).Row)
            End If
        Next
        Return plstRows.ToArray()
    End Get
Mario T. Lanza
źródło
Lubię programowanie funkcjonalne, ale od krótkiego spojrzenia na kod wolałbym podejście „imperatywne” (nazywam deklaratywne ). O wiele łatwiej jest mi czytać - pod warunkiem, że może to być moje doświadczenie i być produktem mojego środowiska. To powiedziawszy, z szybkich 5 sekund widzę kroki przygotowawcze i to, co jest zwracane. Widzę, że istnieje pętla i wiem, że korekty tych danych najprawdopodobniej nastąpiłyby w nich. Nie muszę śledzić definicji funkcji; tam jest, to proste. Ale FP jest czystszy i po przekroczeniu krzywej uczenia się prawdopodobnie równie szybko można by go kodować.
vol7ron
Problemem jest krzywa uczenia się, zwłaszcza podczas pracy z ludźmi, którzy znają „wystarczająco” wielu języków. Jeśli specjalizuję się w jakimś konkretnym języku, jestem pewien, że FP byłoby lepszą pierwszą próbą. Wtedy, gdyby wystąpiły nieefektywności (wydajność testu jednostkowego), można by bardziej wyrazić ich implementacje.
vol7ron

Odpowiedzi:

11

Programowanie funkcjonalne jest zbyt skomplikowane dla niedoświadczonych programistów . Jedną z ilustracji jest ta , na której uczniowie zadeklarowali, że bałagan 30-LOC jest łatwiejszy i bardziej intuicyjny do zrozumienia w porównaniu do czteroliniowego analogu FP.

(Jest to oryginalna wersja przykładu FP, ponieważ odpowiedź w linku została ostatnio edytowana, aby ułatwić jej czytanie).

return this.Data.Products
    .Where(c => c.IsEnabled)
    .GroupBy(c => c.Category)
    .Select(c => new PricesPerCategory(category: c.Key, minimum: c.Min(d => d.Price), maximum: c.Max(d => d.Price)));

Programowanie funkcjonalne wymaga innego sposobu myślenia o naszym sposobie kodowania i sposobie wykonania tego kodu. Rzadko tak mówi się uczniom na studiach, a po złych nawykach trudno je zmienić.

Programowanie funkcjonalne ma również swoje specyficzne cechy, które mogą wydawać się ryzykowne w rękach początkujących . Leniwa ocena jest jedną z nich i może upłynąć miesiące, zanim zacznie się rozumieć, dlaczego leniwa ocena jest doskonałą cechą, a nie irytacją.

Dlatego tak wielu początkujących zaczyna programować w językach takich jak PHP, a nie w językach takich jak Haskell.

Arseni Mourzenko
źródło
8
Mam odwrotne doświadczenie na uniwersytecie, gdzie Scheme jest używany do kursu wprowadzającego. Kiedy uczniowie musieli nauczyć się języka Java lub C #, większość narzekała, że ​​Schemat jest bardziej czytelny
Daniel Gratzer
2
To potwierdza mój punkt widzenia. Studenci, którzy od lat uczyli się programowania imperatywnego i OOP, uznaliby go za bardziej czytelny. Ludzie, którzy rozpoczęli pracę z FP, uznają to za bardziej czytelne w porównaniu do programowania imperatywnego. Byłoby interesujące wiedzieć, co dzieje się z uczniami, którzy znają równie dobrze paradygmaty FP i inne niż FP.
Arseni Mourzenko
1
Głównym problemem jest to, że języki funkcjonalne są abstrakcyjne. Kiedy Haskeller mówi ci, że zabrakło ci pamięci, ponieważ zgromadziłeś nieocenione gromady, to na pewno coś jest nie tak. Wiele algorytmów nie jest wydajnych, gdy są napisane w funkcjonalnym stylu. Nie można wdrożyć szybkiego implantu Quicksort. w idiomatic Haskell. Każdy algorytm lokalny kończy się wykonywaniem tablic IO w celu uzyskania dobrej wydajności. Języki funkcjonalne są dla purystów językowych, języki imperatywne są dla ludzi, którzy chcą, aby myśli zostały wykonane na czas.
Kr0e
3
@ Kr0e: argument „zbyt dużo abstrakcji” przeciwko językowi lub paradygmatowi zawsze wydaje mi się dziwny. Ten sam argument zastosowano wobec wszystkich (lub większości) języków; mam nadzieję, że większość oprogramowania nie jest dziś napisana w asemblerze.
Arseni Mourzenko
6
„Języki funkcjonalne są dla purystów językowych, języki imperatywne są dla ludzi, którzy chcą, aby myśli zostały wykonane na czas.”: Z mojego doświadczenia wynika, że ​​nie jest to prawdą. Mogę szybciej wykonywać zadania, używając funkcjonalnych języków. Tryb rozkazujący jest znacznie bardziej szczegółowy i mniej deklaratywny, a kiedy muszę użyć trybu rozkazującego, zdecydowanie potrzebuję więcej iteracji, zanim wszystko będzie dobrze.
Giorgio,