Czy możliwe jest funkcjonalne programowanie GUI? [Zamknięte]


404

Niedawno złapałem błąd FP (próbując nauczyć się Haskella) i byłem pod wielkim wrażeniem tego, co do tej pory widziałem (pierwszorzędne funkcje, leniwa ocena i wszystkie inne zalety). Nie jestem jeszcze ekspertem, ale zacząłem już łatwiej rozumować „funkcjonalnie” niż bezwzględnie dla podstawowych algorytmów (i mam problem z powrotem tam, gdzie muszę).

Jednak jedynym obszarem, w którym wydaje się, że obecny FP jest płaski, jest programowanie GUI. Podejście Haskell wydaje się polegać tylko na pakowaniu imperatywnych zestawów narzędzi GUI (takich jak GTK + lub wxWidgets) i używaniu bloków „do” do symulacji stylu imperatywnego. Nie korzystałem z F #, ale rozumiem, że robi coś podobnego przy użyciu OOP z klasami .NET. Oczywiście jest ku temu dobry powód - obecne programowanie GUI dotyczy IO i efektów ubocznych, więc czysto funkcjonalne programowanie nie jest możliwe w przypadku większości obecnych frameworków.

Moje pytanie brzmi: czy możliwe jest funkcjonalne podejście do programowania GUI? Mam problem z wyobrażeniem sobie, jak to wyglądałoby w praktyce. Czy ktoś zna jakieś frameworki, eksperymentalne lub inne, które próbują tego rodzaju rzeczy (a nawet jakiekolwiek frameworki, które są zaprojektowane od podstaw dla funkcjonalnego języka)? Czy może rozwiązaniem jest zastosowanie podejścia hybrydowego z OOP dla części GUI i FP dla logiki? (Po prostu pytam z ciekawości - chciałbym myśleć, że FP to „przyszłość”, ale programowanie GUI wydaje się być dość dużą dziurą do wypełnienia.)


7
Po obejrzeniu GUI w Common Lisp i OCaml powiedziałbym, że bardziej prawdopodobne jest lenistwo Haskella, które powoduje problem.
new123456

5
@ new123456 Common Lisp nie jest jednak językiem funkcjonalnym, działa ze zmiennymi danymi i obejmuje skutki uboczne
Electric Coffee

3
@ElectricCoffee Lisp to niezwykle elastyczny język, który można stosować w wielu różnych stylach, a wiele osób decyduje się na używanie Lisp w funkcjonalnym stylu.
chrismamo1

7
Z mojego doświadczenia (choć wciąż staram się w to wierzyć i uczyć się więcej) FRP naprawdę osiąga swój limit dzięki programowaniu GUI; jest ładny i elegancki w przypadku 80% przypadków użycia, ale bogate widżety wymagają bardzo precyzyjnej kontroli stanu wewnętrznego (np. pola kombi wyszukiwania itp.), a FRP po prostu przeszkadza. Imperatyw nie zawsze jest zły; próba zminimalizowania ilości kodu imperatywnego jest dobra, ale usunięcie go w 100%? Nie widziałem, aby działało to w przypadku trywialnego interfejsu użytkownika.
AlexG

8
@ElectricCoffee „Common Lisp nie jest językiem funkcjonalnym”. Lisp jest matką wszystkich języków funkcjonalnych. Masz na myśli, że Lisp nie jest czysty.
Jon Harrop

Odpowiedzi:


183

Podejście Haskell wydaje się polegać tylko na pakowaniu imperatywnych zestawów narzędzi GUI (takich jak GTK + lub wxWidgets) i używaniu bloków „do” w celu symulacji stylu imperatywnego

To nie jest tak naprawdę „podejście Haskell” - tak właśnie łączy się bezpośrednio z niezbędnymi zestawami narzędzi GUI - za pomocą interfejsu imperatywnego. Haskell po prostu ma dość wyraźne wiązania.

Istnieje kilka umiarkowanie dojrzałych lub bardziej eksperymentalnych czysto funkcjonalnych / deklaratywnych podejść do GUI, głównie w Haskell, i przede wszystkim z wykorzystaniem programowania funkcjonalnego reaktywnego.

Oto niektóre przykłady:

Dla tych z Was, którzy nie znają Haskell, Flapjax, http://www.flapjax-lang.org/ to implementacja funkcjonalnego programowania reaktywnego na JavaScript.


32
Zobacz artykuł Conala Elliotta o owocach, aby uzyskać doskonały, dogłębny opis techniki i decyzji: conal.net/papers/genuinely-functional-guis.pdf Od kilku miesięcy zajmuję się czysto funkcjonalnym programowaniem GUI w tym stylu . Uwielbiam to, jest to tak przyjemna ulga od piekła spaghetti imperatywnego programowania interfejsu użytkownika, który wydaje się gorszy pod tym względem niż większość imperatywnego programowania.
luqui

44
W 100% się z tym zgadzam. Aby było to jasne: powodem, dla którego często używane są istniejące zestawy narzędzi GUI, jest to, że istnieją. Powodem, dla którego interfejsy do nich są imperatywne i nieczyste, jest to, że zestawy narzędzi są imperatywne i nieczyste. Powodem, dla którego zestawy narzędzi są imperatywne i nieczyste, jest to, że systemy operacyjne, od których są zależne, są imperatywne i nieczyste. Jednak nie ma nic zasadniczo wymagającego, aby którykolwiek z nich był nieczysty: istnieją funkcjonalne powiązania dla tych zestawów narzędzi, istnieją funkcjonalne zestawy narzędzi, są nawet funkcjonalne systemy operacyjne.
Jörg W Mittag,

16
To wszystko tylko lenistwo. (Zamierzony zły kalambur).
Jörg W Mittag,

10
Pewnego dnia cały projekt GUI zostanie zaimplementowany przez WYSIWYG, a logika zaimplementowana funkcjonalnie. To jest moja prognoza.
BlueRaja - Danny Pflughoeft

23
Wspomniane luqui w gazetach wydają się martwe. Istnieje jednak działający link na stronie Conal Elliott: conal.net/papers/genuinely-functional-guis.pdf
aganders3

74

Moje pytanie brzmi: czy możliwe jest funkcjonalne podejście do programowania GUI?

Kluczowe słowa, których szukasz, to „funkcjonalne programowanie reaktywne” (FRP).

Conal Elliott i inni stworzyli trochę przemysłu chałupniczego, próbując znaleźć odpowiednią abstrakcję dla FRP. W Haskell istnieje kilka implementacji koncepcji FRP.

Możesz rozważyć rozpoczęcie od najnowszego artykułu Conala „Funkcjonalne programowanie reaktywne w trybie push-pull” , ale istnieje kilka innych (starszych) implementacji, niektóre z nich powiązane ze strony haskell.org . Conal ma talent do zajmowania się całą domeną, a jego artykuł można przeczytać bez odniesienia do tego, co było wcześniej.

Aby przekonać się, w jaki sposób można zastosować to podejście do tworzenia GUI, warto spojrzeć na Fudgets , które, choć ostatnio stają się coraz bardziej popularne, zaprojektowane w połowie lat 90., stanowią solidne podejście FRP do projektowania GUI.


Chciałbym dodać wzrost użycia „Reactive Extensions” (biblioteki FRP; jednak nie FP), który został pierwotnie napisany dla C #, a następnie przeniesiony na Javę (RxJava) i JavaScript (RxJS) i różne języki. Sprawdź reactivex.io W tym momencie Angular 2 szeroko wykorzystuje RxJS.
srph

63

Windows Presentation Foundation jest dowodem na to, że funkcjonalne podejście działa bardzo dobrze w programowaniu GUI. Ma wiele aspektów funkcjonalnych, a „dobry” kod WPF (poszukiwanie wzorca MVVM) podkreśla funkcjonalne podejście nad koniecznością. Mógłbym śmiało twierdzić, że WPF jest najbardziej udanym zestawem funkcjonalnych GUI w świecie rzeczywistym :-)

WPF opisuje interfejs użytkownika w XAML (chociaż można go przepisać do funkcjonalnie wyglądającego C # lub F #), więc aby utworzyć interfejs, należy napisać:

<!-- Declarative user interface in WPF and XAML --> 
<Canvas Background="Black">
   <Ellipse x:Name="greenEllipse" Width="75" Height="75" 
      Canvas.Left="0" Canvas.Top="0" Fill="LightGreen" />
</Canvas>

Ponadto WPF pozwala również deklaratywnie opisywać animacje i reakcje na zdarzenia przy użyciu innego zestawu deklaratywnych znaczników (znowu to samo można zapisać jako kod C # / F #):

<DoubleAnimation
   Storyboard.TargetName="greenEllipse" 
   Storyboard.TargetProperty="(Canvas.Left)"
   From="0.0" To="100.0" Duration="0:0:5" />

W rzeczywistości myślę, że WPF ma wiele cech wspólnych z FRP Haskella (choć uważam, że projektanci WPF nie wiedzieli o FRP i jest to trochę niefortunne - WPF czasami wydaje się dziwne i niejasne, jeśli używasz funkcji punkt widzenia).


12
Chociaż XAML ma bardzo deklaratywny charakter, to czy MVVM naprawdę zachęca do funkcjonalnego stylu programowania? Całe pojęcie modelu widoku, którego zadaniem jest śledzenie stanu widoku (i implementuje interfejs zwany INotifyPropertyChangedwszystkimi rzeczami), wydaje mi się dla FP sprzeczne z hipotezą. Zdecydowanie nie jestem ekspertem od FP i może zbytnio skupiam się na aspekcie niezmienności w przeciwieństwie do aspektu deklaratywnego, ale mam problem z dostrzeżeniem, w jaki sposób wzorzec MVVM (jak zwykle używany) jest przykładem FP.
devuxer

1
@devuxer Twierdzę, że tak. Nie sądzę, aby ktokolwiek realistycznie użyłby FP do ścisłego niezmiennego kodu. Zamiast tego decydujesz, gdzie są twoje granice zmienności i pracujesz niezmiennie na wszystkich innych poziomach - w tym przypadku każdy może założyć, że stan jest niezmienny, z wyjątkiem tej jednej niewielkiej części, która faktycznie mutuje stan. Jest podobny do tego, jak działa HTML - tak, masz niezmienny DOM, ale za każdym razem, gdy nawigujesz, wciąż musisz zbudować nowy. INotifyPropertyChangedto tylko funkcja aktualizacji, którą przekazujesz wszędzie tam, gdzie musisz obsłużyć aktualizacje GUI - to naprawa opóźnienia.
Luaan,

3
Steven Pemberton napisał 2 świetne posty na F # i WPF, jego przemyślenia na temat rozwoju WPF z F # pod koniec drugiego postu dodają do tej dyskusji. 2 inne przykłady, które mnie również zaintrygowały, to użycie funkcjonalnego kontrolera w MVVM sterowanym zdarzeniami oraz zastosowanie dyskryminowanych związków i rekurencja do budowy prostego interfejsu w demo sterowania WPF przez Flying Frog Consultancy.
Funk

29

Powiedziałbym, że programowanie funkcjonalne (F #) jest znacznie lepszym narzędziem do programowania interfejsu użytkownika niż na przykład C #. Musisz tylko pomyśleć o problemie nieco inaczej.

Omawiam ten temat w mojej książce o programowaniu funkcjonalnym w rozdziale 16, ale dostępny jest bezpłatny fragment , który pokazuje (IMHO) najciekawszy wzorzec, którego można użyć w języku F #. Powiedz, że chcesz zastosować rysunek prostokątów (użytkownik naciska przycisk, porusza myszą i zwalnia przycisk). W F # możesz napisać coś takiego:

let rec drawingLoop(clr, from) = async { 
   // Wait for the first MouseMove occurrence 
   let! move = Async.AwaitObservable(form.MouseMove) 
   if (move.Button &&& MouseButtons.Left) = MouseButtons.Left then 
      // Refresh the window & continue looping 
      drawRectangle(clr, from, (move.X, move.Y)) 
      return! drawingLoop(clr, from) 
   else
      // Return the end position of rectangle 
      return (move.X, move.Y) } 

let waitingLoop() = async { 
   while true do
      // Wait until the user starts drawing next rectangle
      let! down = Async.AwaitObservable(form.MouseDown) 
      let downPos = (down.X, down.Y) 
      if (down.Button &&& MouseButtons.Left) = MouseButtons.Left then 
         // Wait for the end point of the rectangle
         let! upPos = drawingLoop(Color.IndianRed, downPos) 
         do printfn "Drawn rectangle (%A, %A)" downPos upPos }

Jest to bardzo imperatywne podejście (w zwykłym pragmatycznym stylu F #), ale pozwala uniknąć użycia stanu zmiennego do przechowywania aktualnego stanu rysowania i do przechowywania początkowej lokalizacji. Może być jeszcze bardziej funkcjonalny, napisałem bibliotekę, która robi to w ramach mojej pracy magisterskiej, która powinna być dostępna na moim blogu w ciągu najbliższych kilku dni.

Funkcjonalne programowanie reaktywne jest bardziej funkcjonalnym podejściem, ale korzystanie z niego jest nieco trudniejsze, ponieważ opiera się na dość zaawansowanych funkcjach Haskell (takich jak strzałki). Jest jednak bardzo elegancki w wielu przypadkach. Ograniczeniem jest to, że nie można łatwo zakodować automatu stanów (który jest przydatnym modelem mentalnym dla programów reaktywnych). Jest to bardzo łatwe przy użyciu powyższej techniki F #.


7
+1 To odzwierciedla nasze doświadczenie, ponieważ napisaliśmy kilka produkcyjnych GUI w języku F # przy użyciu bibliotek kombinatora i IObservable.
Jon Harrop

Czy komentarz dotyczący FRP zmienił się od czasu wprowadzenia reaktywnych rozszerzeń do biblioteki .NET?
Fsharp Pete

1
Oto kilka badań dotyczących Arrowized FRP i tego, w jaki sposób efekty i mutacje mogą być osadzone w Arrowized FRP bez łamania praw: haskell.cs.yale.edu/wp-content/uploads/2015/10/... (przy okazji większość bibliotek FRP używa Monad, a nawet Wnioski, więc strzały są niepoprawne).
Erik Kaplun

17

Nieważne, czy jesteś w hybrydowym funkcjonalnej / oo języka jak F # lub SML, lub w języku czysto funkcjonalnego jak Haskell, gdzie skutki uboczne są spadł do IO monady, to najczęściej zdarza się, że mnóstwo pracy wymagane do zarządzania GUI jest znacznie bardziej jak „efekt uboczny” niż czysto funkcjonalny algorytm.

To powiedziawszy, przeprowadzono kilka naprawdę solidnych badań nad funkcjonalnymi GUI . Istnieją nawet (głównie) funkcjonalne zestawy narzędzi, takie jak Fudgets lub FranTk .


6
uszkodzony „funkcjonalny interfejs GUI” :( buforowane: webcache.googleusercontent.com/search?q=cache:http://…
Dan Burton


12

Jednym z otwierających umysły pomysłów na funkcjonalne programowanie reaktywne jest posiadanie funkcji obsługi zdarzeń, ZARÓWNO reakcję na zdarzenia ORAZ następnej funkcji obsługi zdarzeń. W ten sposób ewoluujący system jest reprezentowany jako sekwencja funkcji obsługi zdarzeń.

Dla mnie nauka Yampy stała się kluczową sprawą, aby poprawnie uzyskać funkcje produkujące funkcje. Jest kilka fajnych artykułów na temat Yampy. Polecam The Yampa Arcade:

http://www.cs.nott.ac.uk/~nhn/Talks/HW2003-YampaArcade.pdf (slajdy, PDF) http://www.cs.nott.ac.uk/~nhn/Publications/hw2003. pdf (pełny artykuł, PDF)

Istnieje strona wiki na Yampa na Haskell.org

http://www.haskell.org/haskellwiki/Yampa

Oryginalna strona główna Yampa:

http://www.haskell.org/yampa (obecnie niestety jest zepsuty)


1
Ten link jest zerwany przez długi czas. Spróbuj tego Yampa
KR

7

Od momentu postawienia tego pytania Elm sprawił, że funkcjonalne programowanie reaktywne stało się bardziej popularne.

Proponuję sprawdzić to na stronie http://elm-lang.org , która zawiera również kilka naprawdę doskonałych interaktywnych samouczków na temat tworzenia w pełni funkcjonalnego GUI w przeglądarce.

Pozwala tworzyć w pełni funkcjonalne GUI, w których kod, który sam musisz podać, składa się wyłącznie z czystych funkcji. Osobiście uważałem, że łatwiej jest się do niego dostać niż różne frameworki GUI Haskell.



6

Rozmowę Elliota na temat FRP można znaleźć tutaj .

Ponadto nie jest to tak naprawdę odpowiedź, ale uwaga i kilka przemyśleń : w pewnym sensie termin „funkcjonalny GUI” przypomina trochę oksymoron (czystość i IO w tym samym znaczeniu).

Ale moje niejasne zrozumienie jest takie, że funkcjonalne programowanie GUI polega na deklaratywnym zdefiniowaniu funkcji zależnej od czasu, która pobiera (zależne od czasu) dane wejściowe użytkownika i tworzy zależne od czasu dane wyjściowe GUI.

Innymi słowy, funkcja ta jest zdefiniowana deklaracyjnie jak równanie różniczkowe, zamiast przez algorytm bezwzględnie wykorzystujący stan zmienny.

Tak więc w konwencjonalnym FP używa się funkcji niezależnych od czasu, podczas gdy we FRP używa się funkcji zależnych od czasu jako elementów składowych do opisu programu.

Zastanówmy się nad symulacją piłki na sprężynie, z którą użytkownik może wchodzić w interakcje. Pozycja piłki jest wyjściem graficznym (na ekranie), użytkownik popychający piłkę to naciśnięcie klawisza (wejście).

Opisanie tego programu symulacyjnego we FRP (zgodnie z moim rozumieniem) odbywa się za pomocą jednego równania różniczkowego (deklaratywnie): przyspieszenie * masa = - rozciągnięcie sprężyny * stała sprężyny + siła wywierana przez użytkownika.

Oto wideo na temat ELM, które ilustruje ten punkt widzenia.


5

Od 2016 r. Istnieje kilka innych, stosunkowo dojrzałych platform FRP dla Haskell, takich jak Sodium i Reflex (ale także Netwire).

Książka Manning na funkcyjną reagującą Programowanie gablotach wersja Java sód przykładów roboczych i ilustruje, w jaki sposób zachowuje się baza kodu FRP GUI i wagi w porównaniu z bezwzględnym, jak podejść opartych aktora.

Istnieje również najnowszy artykuł na temat Arrowized FRP i perspektywy włączenia efektów ubocznych, IO i mutacji do zgodnych z prawem, czystych ustawień FRP: http://haskell.cs.yale.edu/wp-content/uploads/2015/10/ dwc-yale-formatted-dissertation.pdf .

Warto również zauważyć, że frameworki JavaScript, takie jak ReactJS i Angular, i wiele innych już stosuje lub zbliża się do korzystania z FRP lub innego funkcjonalnego podejścia do uzyskania skalowalnych i możliwych do skomponowania komponentów GUI.


Sód został przestarzały na rzecz reaktywnego banana zgodnie z
readith


3

Aby rozwiązać ten problem, zamieściłem kilka moich przemyśleń na temat używania F #,

http://fadsworld.wordpress.com/2011/04/13/f-in-the-enterprise-i/ http://fadsworld.wordpress.com/2011/04/17/fin-the-enterprise-ii- 2 /

Planuję również zrobić samouczek wideo, aby dokończyć serię i pokazać, w jaki sposób F # może przyczynić się do programowania UX.

Mówię tu tylko w kontekście F #.

-Fahad


2

Wszystkie pozostałe odpowiedzi są oparte na programowaniu funkcjonalnym, ale podejmują wiele własnych decyzji projektowych. Jedną biblioteką zbudowaną zasadniczo całkowicie z funkcji i prostych abstrakcyjnych typów danych jest gloss. Oto typ jego playfunkcji ze źródła

-- | Play a game in a window. Like `simulate`, but you manage your own input events.
play    :: Display              -- ^ Display mode.
        -> Color                -- ^ Background color.
        -> Int                  -- ^ Number of simulation steps to take for each second of real time.
        -> world                -- ^ The initial world.
        -> (world -> Picture)   -- ^ A function to convert the world a picture.
        -> (Event -> world -> world)    
                -- ^ A function to handle input events.
        -> (Float -> world -> world)
                -- ^ A function to step the world one iteration.
                --   It is passed the period of time (in seconds) needing to be advanced.
        -> IO ()

Jak widać, działa całkowicie, dostarczając czyste funkcje z prostymi typami abstrakcyjnymi, w czym pomagają inne biblioteki.


1

Najbardziej widoczną innowacją zauważoną przez nowych użytkowników Haskell jest oddzielenie nieczystego świata związanego z komunikowaniem się ze światem zewnętrznym od czystego świata obliczeń i algorytmów. Często zadawane pytanie dla początkujących brzmi: „Jak się pozbyć IO, tzn. Zamienić IO ana a?”. Sposób na to polega na użyciu monad (lub innych abstrakcji) do napisania kodu wykonującego efekty IO i łańcuchowe. Ten kod zbiera dane ze świata zewnętrznego, tworzy jego model, wykonuje pewne obliczenia, prawdopodobnie wykorzystując czysty kod i generuje wynik.

Jeśli chodzi o powyższy model, nie widzę nic strasznie złego w manipulowaniu GUI w IOmonadzie. Największym problemem wynikającym z tego stylu jest to, że moduły nie są już możliwe do skomponowania, tzn. Tracę większość mojej wiedzy na temat globalnej kolejności wykonywania instrukcji w moim programie. Aby go odzyskać, muszę zastosować podobne rozumowanie jak w przypadku współbieżnego, bezwzględnego kodu GUI. Tymczasem w przypadku nieczystego kodu bez GUI kolejność wykonywania jest oczywista ze względu na definicję operatora IOmonady >==(przynajmniej tak długo, jak istnieje tylko jeden wątek). W przypadku czystego kodu nie ma to żadnego znaczenia, z wyjątkiem przypadków narożnych, aby zwiększyć wydajność lub uniknąć wyników oceny .

Największą filozoficzną różnicą między konsolowym a graficznym We / Wy jest to, że programy implementujące te pierwsze są zwykle pisane w stylu synchronicznym. Jest to możliwe, ponieważ istnieje (pomijając sygnały i inne otwarte deskryptory plików) tylko jedno źródło zdarzeń: powszechnie nazywany strumień bajtów stdin. GUI są z natury asynchroniczne i muszą reagować na zdarzenia z klawiatury i kliknięcia myszą.

Popularna filozofia wykonywania asynchronicznych operacji we / wy w sposób funkcjonalny nosi nazwę Functional Reactive Programming (FRP). Ostatnio zyskał dużą przyczepność w nieczystych, niefunkcjonalnych językach dzięki bibliotekom takim jak ReactiveX i frameworkom takim jak Elm. W skrócie, to jak przeglądanie elementów GUI i innych rzeczy (takich jak pliki, zegary, alarmy, klawiatura, mysz) jako źródeł zdarzeń, zwanych „obserwowalnymi”, które emitują strumienie zdarzeń. Zdarzenia te są łączone za pomocą znanych, takich jak operatorzy map, foldl, zip, filter, concat, join, itd., W celu wytworzenia nowych strumieni. Jest to przydatne, ponieważ sam stan programu może być postrzegany jako scanl . map reactToEvents $ zipN <eventStreams>program, gdzie Njest równy liczbie obserwowalnych kiedykolwiek rozważanych przez program.

Praca z obserwowalnymi FRP pozwala odzyskać kompozycję, ponieważ zdarzenia w strumieniu są uporządkowane w czasie. Powodem jest to, że abstrakcja strumienia zdarzeń umożliwia wyświetlanie wszystkich obserwowalnych obiektów jako czarnych skrzynek. Ostatecznie połączenie strumieni zdarzeń za pomocą operatorów zwróci niektóre lokalne porządki przy wykonywaniu. Zmusza mnie to do większej szczerości w kwestii niezmienników, na których faktycznie polega mój program, podobnie do tego, w jaki sposób wszystkie funkcje w Haskell muszą być referencyjnie przejrzyste: jeśli chcę pobierać dane z innej części mojego programu, muszę wyrazić się jasno reklama deklaruje odpowiedni typ dla moich funkcji. (Monada IO, będąca językiem specyficznym dla domeny do pisania nieczystego kodu, skutecznie to omija)


-22

Programowanie funkcjonalne mogło się zmienić od czasu, gdy byłem na uniwersytecie, ale o ile pamiętam, głównym celem funkcjonalnego systemu programowania było powstrzymanie programisty przed jakimkolwiek „efektem ubocznym”. Jednak użytkownicy kupują oprogramowanie z powodu tworzonych efektów ubocznych, np. Aktualizacji interfejsu użytkownika.


25
Myślę, że źle zrozumiałeś: nie jest tak, że programowanie funkcjonalne nie ma wpływu zewnętrznego na świat - to uczyniłoby wszystkie programy całkowicie bezużytecznymi! Zamiast tego programowanie funkcjonalne pozwala poddać kwarantannie operacje we / wy, abyś wiedział, które bity go używają, a które nie.
Tikhon Jelvis,

Whoooooooosh x20
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.