2014-04-01 19 views
5

Niedawno widziałem this ciekawą prezentację o programowaniu reaktywnym w Elm.Czy można przetłumaczyć przykład z Mario z Elm na czysty JavaFX lub JavaFX + RxJava, zachowując przy tym wysoki poziom abstrakcji Wiąz?

To sprawiło, że zastanawiam się, czy konstrukcje językowe używane do realizacji gra Mario (w przedstawionej prezentacji, a także na zdjęciu poniżej) mogą być odwzorowywane na podobnym wysokim poziomie języku konstruuje zarówno w czystej JavaFX lub w JavaFX połączeniu z RxJava?

Innymi słowy, czy możliwe byłoby wyrażenie gry Mario zaimplementowanej w Wiąz przy użyciu tych samych abstrakcji pojęciowych (tj. Wartości zależnych od czasu) w samym JavaFX lub w JavaFX + RxJava?

Więc jeśli doświadczony 1) programista JavaFX lub doświadczony 2) Programista JavaFX + RxJava + funkcjonalny chce przenieść grę Mario z Elma na 1) JavaFX lub 2) JavaFX + RxJava, który programista może wykonać to zadanie przez używając podobnych abstrakcji wysokiego poziomu jak użyto w Wiąz?

Abstrakcje, które mam na myśli dla JavaFX, to powiązania, a dla JavaFX + RxJava są powiązania + Obserwowalne/Tematy/Subskrypcja.

enter image description here

Odpowiedz

7

Szybko rzuciłem okiem na Elm i jest to imponujące (i wyraziste).

W Elm skonstruować swoją scenę jako

Signal Element 

który w JavaFX byłaby grubsza odpowiada

ObservableValue<Node> 

tłumaczenie naiwne JavaFX oznaczałoby, że zamienić całą scenę na każdej aktualizacji, która jest niezwykle kosztowne. W Elmie Element jest niezmienną abstrakcyjną reprezentacją węzła sceny, zbudowanego poza ekranem (poza DOM). Jest wystarczająco tani, aby odtworzyć cały wykres sceny przy każdej aktualizacji (ze względu na niezmienność, bezpieczne jest ponowne użycie niezmienionych gałęzi). Root Element jest renderowany do DOM, ale, jak rozumiem, tylko po raz pierwszy skonstruowany jest pełny DOM. Przy kolejnych aktualizacjach środowisko wykonawcze Elm uruchamia algorytm do porównywania nowego elementu głównego ze starym i modyfikuje tylko te części DOM, które wymagają aktualizacji, co jest wystarczająco szybkie. Ta sama technika jest używana przez React.js. Zatem zarówno Elm, jak i React.js zapewniają funkcjonalną abstrakcję na wysokim poziomie, ale wykorzystują zmienność pod osłonami ze względu na wydajność.

Z dodatkowym szumem syntaktycznym można przetłumaczyć większość konstrukcji Elm na JavaFX (*). Na przykład,

lift2 display Window.dimensions gameState 

jest równoważna

import static org.fxmisc.EasyBind.*; 

combine(Window.dimensions, gameState, display) 

brakującym elementem jest biblioteka niezmiennych reprezentacji streszczenie widget i ich wydajne renderowanie w JavaFX wykresie sceny.

Co można zrobić, to:

  • stworzyć taką bibliotekę widget dla JavaFX;
  • lub nawet skompiluj Wiąz do JavaFX (zamiast HTML + JavaScript).

Chciałbym zobaczyć jedną z tych rzeczy.


(*) Myślę Elm records są bardzo silne i wymagałoby dużo z boilerplate w Javie (lub Scala).

Elm:

type Point = { x:Float, y:Float } 

p = { 0.0, 0.0 } 
q = { p | x <- 5.0 } 

Java:

class Point { 
    public final float x; 
    public final float y; 

    public Point(float x, float y) { 
     this.x = x; 
     this.y = y; 
    } 

    public Point updateX(float x) { 
     return new Point(x, y); 
    } 

    public Point updateY(float y) { 
     return new Point(x, y); 
    } 
} 

Point p = new Point(0.0, 0.0); 
Point q = p.updateX(5.0); 

Scala:

case class Point(x: Float, y: Float) 

val p = Point(0.0, 0.0) 
val q = p.copy(x = 5.0f) 
+0

Bardzo precyzyjna odpowiedź pokazująca zgodność między Elm i JavaFX! Ta odpowiedź pomoże mi nawet w mojej pracy magisterskiej. (Btw, dobra robota na ReactFX, jej przykłady na twoim [blogu] (http://tomasmikula.github.io/blog/2014/04/25/combining-reactfx-and-asynchronous-processing.html) są imponujące. zaplanowałem część dotyczącą ReactFX w mojej pracy magisterskiej.) – Eugen

+0

Dziękuję za szczegółową odpowiedź. A co z tłumaczeniem konstruktów Elma na JavaFX + RXJava? Czy byłoby łatwiej (mniej skromniej) w porównaniu z tłumaczeniem konstrukcji Elma na JavaFX? – jhegedus

+0

Nie sądzę. Płyta wzorcowa jest spowodowana brakiem elementów Wiązania _ języka Java, takich jak silniejsze wnioskowanie typów, aliasy typów, typy rekordów ... Żadne biblioteki Java nie dodadzą tego do języka. Funkcjonowanie czystych (bez efektów ubocznych) funkcji i niezmiennych obiektów nie może być egzekwowane w Javie, ale można je osiągnąć dzięki własnej dyscyplinie. Węzły JavaFX można modyfikować według projektu, więc potrzebujesz niezmiennej biblioteki widgetów, o której wspomniałem. Kompozycja funkcji jest dość łatwa dzięki językom Java 8. –

4

mówię, że jest to możliwe, bez faktycznie robi :-)

to tylko przypuszczenie jak mam małe doświadczenie w tej dziedzinie i nikt w ogóle z Elm.

Myślę, że najbliżej Elma stworzysz opakowanie ScalaFX dla ReactFX, choć prawdopodobnie będziesz mógł również użyć lambd do Java 8 w połączeniu z ReactFX zamiast Scala. Najprawdopodobniej będziesz musiał wdrożyć kilka rozszerzeń do ReactFX, a także różnych innych urządzeń, aby uzyskać abstrakcje i elegancję, której pragniesz.

Zamówienie Deprecating the Observer Pattern, jeśli jeszcze tego nie zrobiłeś. Myślę, że jest to bardzo istotne w tym temacie, zwłaszcza jeśli chodzi o myślenie o reaktywnym modelu programowania, w przeciwieństwie do modelu obserwowalnego (czyli JavaFX ChangeListeners). To powiedziawszy, myślę, że jeśli użyjesz bibliotek takich jak ReactFX, które są zbudowane na strukturze JavaFX i strukturach nasłuchujących, prawdopodobnie skończysz z wyższym poziomem abstrakcji strumieni zdarzeń, które są przydatne do programowania reaktywnego.

Oczywiście, możesz zrobić grę Mario w JavaFX bez użycia ReactFX, ale kod będzie zupełnie inny i będziesz pracował na innym poziomie abstrakcji do tego, czego używałbyś z ReactFX. Tak czysty JavaFX, bez ReactFX będzie mniej Wiązów podobnych.

Dla warstwy sieciowej, akka może być użyty do stworzenia reaktywnej struktury dla gier wieloosobowych, co pozwoliłoby ci używać programowania od góry do dołu, zarówno w twoim interfejsie, jak iw systemie komunikacyjnym.

W przypadku animacji Sprite w próbce Mario należy zastosować kod netopyr dla Creating a Sprite Animation with JavaFX.

Do obliczeń fizyki można użyć biblioteki JBox2D. Trzeba utworzyć coś w rodzaju reaktywnego wrappera wokół JBox2D, aby zdawać sobie sprawę z właściwości takich jak właściwości JavaFX i strumienie zdarzeń i subskrypcje ReactFX. Dla uproszczonej próbki Mario użycie zewnętrznej biblioteki prawdopodobnie byłoby większym problemem niż jej wartość. Zamiast tego możesz użyć podstawowego modelu fizyki domowej (np.coś podobnego do tego ball animation experiment) i podłącz go do swojego reaktywnego frameworka.

Radzę skontaktować się z Tomasem Mikula, który stworzył ReactFX, i poprosić go o reaktywne programowanie na pytania JavaFX. Robert Ladstätter również zrobił kilka fajnych rzeczy z ScalaFX i może być w stanie udzielić ci dalszych porad, chociaż nie wiem, czy w ogóle pracował z programowaniem reaktywnym. Sugerowałbym także pingowanie ScalaFX users forums, ale widzę, że już to zrobiłeś :-)

Elm Mario sample jest dość prosty, więc radzę spróbować tłumaczenia na ReactFX. Wtedy myślę, że odpowiedź na twoje pytanie stanie się oczywista. Teraz, gdy napisałem to =>, jeśli nie zaimplementujesz go i nie opublikujesz rozwiązania jako poprawnej odpowiedzi, być może będę musiał Cię wytropić i nie będziesz chciał :-)

+0

Widzę twój punkt :) wielkie dzięki. Dziękuję za zachęta. – jhegedus

+0

Obecnie czytam Haskell School of Expressions, która ma bardzo interesujący i bardzo wstępny rozdział budowania gier reaktywnych w Haskell. Wciąż jestem całkiem początkującym w tej ciekawej dziedzinie, ale mam nadzieję, że wkrótce będę miał szybki start :) – jhegedus

4

Jestem obecnie porównuje tradycyjne zorientowane obiektowo programowanie GUI z funkcjonalnym programowaniem GUI dla mojej pracy magisterskiej. W rzeczywistości, jedną z części, którą za chwilę rozpocznę, jest użycie Elma do odtworzenia wielu tradycyjnych programów GUI w JavaFX/ScalaFX. Kiedy skończę z tym, prawdopodobnie będę w stanie udzielić bardziej precyzyjnej odpowiedzi, ale nadal chcę zapewnić pewne ogólnie przydatne wskaźniki.


Po pierwsze, istnieją dwa dobre papiery, które stanowią przegląd krajobrazu FRP, mianowicie “A Survey on Reactive Programming“ i “Towards Reactive Programming for Object-oriented Applications”. Ta pierwsza, w szczególności, zapewnia taksonomię systemów FRP, która odróżnia "Rodzeństwo z FRP" i "Kuzyni FRP" (nawiązując do ich pokrewieństwa do idei Fran). Rodzeństwo FRP skupia się na zmiennych w czasie wartościach, kuzyni FRP skupiają się na strumieniach zdarzeń, obserwowalnych kolekcjach i asynchronii i nie mają prymitywnych abstrakcji reprezentujących wartości zmiennych w czasie. Z tym rozróżnieniem na uwadze, Elm jest rodzeństwem FRP i RxJava/ReactFX jest kuzynem FRP. Sądzę, że można powiedzieć, że są one różnych zwierząt, mimo że oba są systemami FRP i naturalnie pokrywają się.

drugie, papier “Crossing State Lines: Adapting Object-Oriented Frameworks to Functional Reactive Languages” zapewnia bardzo miłą i zwięzłe podsumowanie różnic między podejściem FRP jak w Elm i tradycyjnym podejściem OOP jak w JavaFX:

OO sprawia stan wyraźny ale Obejmuje ona, natomiast stan w FRP jest ukryty przed programistą przez czasowe abstrakcje tego języka.

Istnieje zatem zasadniczo odmienne podejście do projektowania programu. Dlatego dla mnie nie jest jeszcze jasne, czy i jak można osiągnąć "te same" abstrakcje wysokiego poziomu za pomocą JavaFX (+ RxJava/ReactFX), jak w przypadku Wiązu. Nie oznacza to, że nie jest to możliwe, ale na pierwszy rzut oka nie jest to oczywiste.

Wreszcie, ogólne spostrzeżenie o Elm i jego skrajnej „obcości” w porównaniu z tradycyjnym podejściem OOP z mojej pracy, aby uczynić przeszkód w osiągnięciu takiego samego rezultatu w JavaFX wyraźniej:

Wiele bibliotek GUI nawet w czysto funkcjonalnych językach jest to w zasadzie cienka podkładka o rozmiarze nad (koniecznym) obiektem GUI. Oznacza to, że dla przykładu, widżety te nie są czystymi funkcjami. Widgety mają stan, a zatem tożsamość.Jeśli metaforycznie podkręcimy pokrętło funkcyjne na tablicy kontrolnej GUI do jego maksymalnej wartości, musimy dojść do sytuacji, w której nawet widżety nie będą niczym innym, jak czystymi funkcjami. Wiąz jest takim przykładem maksymalnie funkcjonalnego zestawu narzędzi językowych i GUI w tym samym czasie. Ponieważ callbacki są związane z efektami ubocznymi Wiąz naturalnie nie używa wywołań zwrotnych dla kodu związanego z zachowaniem, ale zamiast tego dla FRP. Gdzie personalizacja w języku OOP najczęściej uzyskuje się dziedziczenia, w Elm jest tylko droga składzie funkcji ...

Kluczową kwestią jest to, że w Elm widoki są czyste funkcje, a przede wszystkim, Elm zmusza cię do takiego ukształtowania kodu. W JavaFX nie jesteś zmuszany, więc musisz to zrobić celowo.

Nawiasem mówiąc, jest tam game skeleton dla gier Elm takich jak Mario. Możesz go przestudiować i pomyśleć o tym, jak zaprojektowałbyś swój program JavaFX po tym szkielecie. Może po studiach mógłbyś stworzyć taki szkielet dla JavaFX? Byłbym zainteresowany tym.

+1

Brzmi bardzo interesująco, dziękuję za szczegółową odpowiedź! Opublikuj link do swojej pracy, chciałbym przeczytać go po zakończeniu. – jhegedus

+1

Tak, ReactFX dotyczy strumieni zdarzeń, ale zwykły JavaFX ma już zmienne w czasie wartości, a mianowicie ObservableValue. ReactFX zapewnia łatwy sposób na konwersję dwóch: 'EventStreams.valuesOf (obserservValue)' tworzy strumień zdarzeń z obserwowalnej wartości, podczas gdy 'stream.toBinding (initialValue)' zamienia strumień zdarzeń na możliwą do zaobserwowania wartość. –

2

Mam postawione pytanie rok temu. Od tego czasu nauczyłem się dwóch rzeczy o FRP. Myślę, że odpowiedź brzmi nie, przynajmniej niełatwo z RX, byłoby znacznie lepiej użyć biblioteki JavaFX + Sodium FRP.

Dlaczego nie (bardzo łatwo) możliwe z RX? Ponieważ ELM to FRP, a RX to FRP minus transakcje (niejasno mówiąc). Praktycznie więc, gdyby ktoś chciał wdrożyć grę Mario w ELM, musiałaby dodać transakcje do RX (aby uniknąć glitches).