Po przeczytaniu wielu stron o FRP w końcu natknąłem się na to oświecające pismo o FRP, w końcu zrozumiałem, na czym tak naprawdę polega FRP.
Cytuję poniżej Heinricha Apfelmusa (autora reaktywnego banana).
Jaka jest istota funkcjonalnego programowania reaktywnego?
Częstą odpowiedzią byłoby, że „FRP polega na opisaniu systemu w kategoriach funkcji zmieniających się w czasie zamiast stanu zmiennego”, a to z pewnością nie byłoby błędne. To jest semantyczny punkt widzenia. Ale moim zdaniem głębszej, bardziej satysfakcjonującej odpowiedzi udziela następujące czysto składniowe kryterium:
Istotą funkcjonalnego programowania reaktywnego jest całkowite określenie dynamicznego zachowania wartości w momencie deklaracji.
Weźmy na przykład licznik: masz dwa przyciski oznaczone „W górę” i „W dół”, których można użyć do zwiększenia lub zmniejszenia licznika. Koniecznie należy najpierw określić wartość początkową, a następnie ją zmienić po każdym naciśnięciu przycisku; coś takiego:
counter := 0 -- initial value
on buttonUp = (counter := counter + 1) -- change it later
on buttonDown = (counter := counter - 1)
Chodzi o to, że w momencie deklaracji podana jest tylko wartość początkowa licznika; dynamiczne zachowanie licznika jest niejawne w pozostałej części tekstu programu. Natomiast funkcjonalne programowanie reaktywne określa całe zachowanie dynamiczne w momencie deklaracji, takie jak:
counter :: Behavior Int
counter = accumulate ($) 0
(fmap (+1) eventUp
`union` fmap (subtract 1) eventDown)
Ilekroć chcesz zrozumieć dynamikę licznika, musisz tylko spojrzeć na jego definicję. Wszystko, co może się przydarzyć, pojawi się po prawej stronie. Jest to bardzo sprzeczne z imperatywnym podejściem, w którym kolejne deklaracje mogą zmienić dynamiczne zachowanie wcześniej zadeklarowanych wartości.
Tak więc, moim zdaniem, program FRP jest zbiorem równań:

j jest dyskretny: 1,2,3,4 ...
fzależy od ttego, co obejmuje możliwość modelowania bodźców zewnętrznych
cały stan programu jest zamknięty w zmiennych x_i
Biblioteka FRP dba o postęp czasu, innymi słowy, jdo j+1.
Wyjaśniam te równania bardziej szczegółowo w tym filmie.
EDYTOWAĆ:
Około 2 lata po oryginalnej odpowiedzi doszedłem niedawno do wniosku, że implementacje FRP mają jeszcze jeden ważny aspekt. Muszą (i zwykle robią) rozwiązać ważny problem praktyczny: unieważnienie pamięci podręcznej .
Równania dla x_i-s opisują wykres zależności. Kiedy niektóre x_izmiany w danym momencie, jnie wszystkie pozostałe x_i'wartości j+1muszą zostać zaktualizowane, więc nie wszystkie zależności muszą zostać ponownie obliczone, ponieważ niektóre x_i'mogą być niezależne x_i.
Ponadto x_i-s, które się zmieniają, można stopniowo aktualizować. Dla przykładu rozważmy operację mapę f=g.map(_+1)w Scala, gdzie fi gsą Listod Ints. Tutaj fodpowiada x_i(t_j)i gjest x_j(t_j). Teraz, jeśli przygotuję do tego element g, byłoby niepotrzebnie przeprowadzić mapoperację dla wszystkich elementów w g. Niektóre implementacje FRP (na przykład reflex-frp ) mają na celu rozwiązanie tego problemu. Ten problem jest również znany jako obliczanie przyrostowe.
Innymi słowy, zachowania ( x_i-s) we FRP można traktować jako obliczenia buforowane. Mechanizm FRP ma za zadanie skutecznie unieważnić i ponownie obliczyć te pamięci podręczne ( x_i-y), jeśli niektóre z f_inich się zmienią.