Próbuję wyobrazić sobie kilka prostych, automatycznych układów fizycznych (takich jak wahadło, ramiona robotów itp.) W Haskell. Często systemy te można opisać równaniami takimi jak
df/dt = c*f(t) + u(t)
gdzie u(t)
reprezentuje rodzaj „inteligentnej kontroli”. Systemy te bardzo dobrze pasują do paradygmatu programowania funkcjonalnego reaktywnego.
Więc złapałem książkę „Haskell Szkołę wyrażenie” przez Paula Hudák, a okazało się, że domena język „FAL” (dla Functional Animacja Język) przedstawił tam faktycznie działa całkiem przyjemnie dla moich prostych systemów zabawki (choć niektórych funkcji, zwłaszcza integrate
, wydawał się nieco zbyt leniwy, aby można go było efektywnie wykorzystać, ale łatwo go naprawić).
Moje pytanie brzmi: jaka jest obecnie bardziej dojrzała, aktualna, dobrze utrzymana, dostrojona pod kątem wydajności alternatywa dla bardziej zaawansowanych, a nawet praktycznych zastosowań?
Ta strona wiki zawiera kilka opcji dla Haskell, ale nie jestem pewien co do następujących aspektów:
Status „reaktywny”, projekt Conala Eliotta, który jest (jak rozumiem) jednym z wynalazców tego paradygmatu programowania, wygląda na nieco przestarzały. Uwielbiam jego kod, ale może powinienem wypróbować inne, bardziej aktualne alternatywy? Jaka jest główna różnica między nimi pod względem składni / wydajności / stabilności czasu wykonywania?
Cytując z ankiety przeprowadzonej w 2011 r., Sekcja 6: „ … implementacje FRP nadal nie są wystarczająco wydajne lub przewidywalne pod względem wydajności, aby można je było skutecznie wykorzystać w domenach, które wymagają gwarancji opóźnienia… ”. Chociaż ankieta sugeruje kilka interesujących możliwych optymalizacji, biorąc pod uwagę fakt, że FRP istnieje od ponad 15 lat, mam wrażenie, że ten problem z wydajnością może być czymś bardzo lub nawet z natury trudnym do rozwiązania przynajmniej w ciągu kilku lat. Czy to prawda?
Ten sam autor ankiety na swoim blogu mówi o „wyciekach czasu” . Czy problem dotyczy wyłącznie FRP, czy jest to coś, z czym mamy do czynienia podczas programowania w czystym, nieostrym języku? Czy kiedykolwiek okazało się, że ustabilizowanie systemu opartego na FRP w czasie było zbyt trudne, jeśli nie było wystarczająco wydajne?
Czy to nadal projekt na poziomie badawczym? Czy ludzie tacy jak inżynierowie fabryk, inżynierowie robotyki, inżynierowie finansowi itp. Faktycznie ich używają (w jakimkolwiek języku, który odpowiada ich potrzebom)?
Chociaż osobiście wolę implementację Haskell, jestem otwarty na inne sugestie. Na przykład, byłoby szczególnie przyjemnie mieć implementację Erlanga - wówczas bardzo łatwo byłoby mieć inteligentny, adaptacyjny, samouczący się proces serwera!
Chociaż jest już kilka dobrych odpowiedzi, spróbuję odpowiedzieć na Twoje konkretne pytania.
reactive nie nadaje się do użytku w poważnych projektach z powodu problemów z upływem czasu. (patrz nr 3). Obecna biblioteka o najbardziej podobnym projekcie to reaktywny banan, który został opracowany z inspiracji reaktywnością i w dyskusji z Conalem Elliottem.
Chociaż sam Haskell jest nieodpowiedni dla trudnych aplikacji czasu rzeczywistego, w niektórych przypadkach można go używać do miękkich aplikacji czasu rzeczywistego. Nie znam aktualnych badań, ale nie wierzę, że jest to problem nie do pokonania. Podejrzewam, że systemy takie jak Yampa lub systemy generowania kodu, takie jak Atom, są prawdopodobnie najlepszym podejściem do rozwiązania tego problemu.
„Przeciek czasu” to problem charakterystyczny dla przełączalnego FRP. Przeciek występuje, gdy system nie jest w stanie uwolnić starych obiektów, ponieważ może ich potrzebować, gdyby w pewnym momencie w przyszłości nastąpiła zmiana. Oprócz wycieku pamięci (który może być dość poważny), inną konsekwencją jest to, że gdy nastąpi przełączenie, system musi wstrzymać działanie, podczas gdy przechodzi łańcuch starych obiektów, aby wygenerować bieżący stan.
Niezłączalne biblioteki frp, takie jak Yampa i starsze wersje reactive-banana, nie cierpią z powodu wycieków czasu. Przełączalne biblioteki frp zazwyczaj stosują jeden z dwóch schematów: albo mają specjalną „monadę tworzenia”, w której tworzone są wartości FRP, albo używają parametru typu „starzenie się”, aby ograniczyć konteksty, w których mogą wystąpić przełączniki. elerea (i prawdopodobnie netwire?) używają tego pierwszego, podczas gdy ostatnie reaktywne banany i grejpfruty używają drugiego.
Przez „przełączalne frp” rozumiem taki, który implementuje funkcję Conala
switcher :: Behavior a -> Event (Behavior a) -> Behavior a
lub identyczną semantykę. Oznacza to, że kształt sieci może się dynamicznie zmieniać w trakcie jej działania.Nie jest to tak naprawdę sprzeczne ze stwierdzeniem @ ertes dotyczącym interfejsów monadycznych: okazuje się, że dostarczenie
Monad
instancji aEvent
umożliwia upływ czasu, a przy żadnym z powyższych podejść nie jest już możliwe zdefiniowanie równoważnych instancji Monady.Wreszcie, chociaż wciąż pozostaje wiele pracy do wykonania z FRP, myślę, że niektóre z nowszych platform (reactive-banana, elerea, netwire) są wystarczająco stabilne i dojrzałe, aby można było z nich zbudować niezawodny kod. Ale być może będziesz musiał spędzić dużo czasu na poznawaniu tajników, aby zrozumieć, jak uzyskać dobrą wydajność.
źródło
Zamierzam wymienić kilka elementów z przestrzeni Mono i .Net oraz jedną z przestrzeni Haskell, którą znalazłem nie tak dawno temu. Zacznę od Haskella.
Wiąz - link
Jego opis na swojej stronie:
Ma swój własny wariant FRP . Zabawa przykładami wydaje się całkiem dojrzała.
Rozszerzenia reaktywne - link
Opis z pierwszej strony:
Reactive Extensions pochodzi z MSFT i implementuje wiele doskonałych operatorów, które upraszczają obsługę zdarzeń. To było open source zaledwie kilka dni temu. Jest bardzo dojrzały i używany w produkcji; moim zdaniem byłby to lepszy interfejs API dla Windows 8 API niż zapewnia biblioteka TPL; ponieważ obserwowalne mogą być zarówno gorące, jak i zimne, ponawiane / scalane itp., Podczas gdy zadania zawsze reprezentują gorące lub wykonane obliczenia, które są uruchomione, błędne lub zakończone.
Napisałem kod po stronie serwera przy użyciu Rx dla asynchroniczności, ale muszę przyznać, że pisanie funkcjonalne w C # może być nieco denerwujące. F # ma kilka otok, ale trudno było śledzić rozwój interfejsu API, ponieważ grupa jest stosunkowo zamknięta i nie jest promowana przez MSFT, tak jak inne projekty.
Jego otwarte źródło pochodziło z otwartym źródłem jego kompilatora IL-to-JS, więc prawdopodobnie może dobrze działać z JavaScript lub Elm.
Prawdopodobnie możesz bardzo ładnie powiązać F # / C # / JS / Haskell za pomocą brokera komunikatów, takiego jak RabbitMQ i SocksJS.
Bling UI Toolkit - link
Opis z pierwszej strony:
Bezpłatny artykuł LtU .
Przetestowałem to, ale nie pracowałem z tym dla projektu klienta. Wygląda niesamowicie, ma ładne przeciążenie operatorów C #, które tworzą powiązania między wartościami. Używa właściwości zależności w WPF / SL / (WinRT) jako źródeł zdarzeń. Animacje 3D działają dobrze na rozsądnym sprzęcie. Użyłbym tego, jeśli skończę na projekcie wymagającym wizualizacji; prawdopodobnie przenosząc go na Windows 8.
ReactiveUI - link
Paul Betts, wcześniej w MSFT, a teraz w Github, napisał ten framework. Pracowałem z nim dość intensywnie i podoba mi się model. Jest bardziej odsprzężony niż Blink (z natury od używania Rx i jego abstrakcji) - co ułatwia testowanie kodu jednostkowego za jego pomocą. W tym jest napisany klient gitub dla systemu Windows.
Komentarze
Model reaktywny jest wystarczająco wydajny dla większości aplikacji wymagających dużej wydajności. Jeśli myślisz o trudnym czasie rzeczywistym, założę się, że większość języków GC ma problemy. Rx, ReactiveUI tworzą pewną ilość małych obiektów, które muszą być poddane GC, ponieważ w ten sposób tworzone / usuwane są subskrypcje, a wartości pośrednie są progresywne w reaktywnej „monadzie” wywołań zwrotnych. Ogólnie w .Net wolę programowanie reaktywne niż programowanie oparte na zadaniach, ponieważ wywołania zwrotne są statyczne (znane w czasie kompilacji, bez alokacji), podczas gdy zadania są przydzielane dynamicznie (nieznane, wszystkie wywołania wymagają instancji, tworzone są śmieci) - a lambdy kompilują się do klasy generowane przez kompilator.
Oczywiście C # i F # są ściśle oceniane, więc przeciek czasu nie stanowi tutaj problemu. To samo dotyczy JS. Może to być jednak problem z odtwarzalnymi lub buforowanymi obserwowalnymi.
źródło
u(t)
i symulacji dlaf(t)
. Czy tak jest w przypadku implementacji języka F #?