Czym jest (funkcjonalne) programowanie reaktywne?

zamknięty. To pytanie i jego odpowiedzi są zamknięte , ponieważ pytanie jest off-topic, ale ma znaczenie historyczne. Obecnie nie przyjmuje nowych odpowiedzi ani interakcji.

Przeczytałem artykuł w Wikipedii NA programowanie reaktywne . Przeczytałem też mały artykuł o functional reactive programming . Opisy są dość abstrakcyjne.

  1. co w praktyce oznacza functional reactive programming (FRP)?
  2. czym jest programowanie reaktywne (w przeciwieństwie do programowania niereaktywnego?/ align = "left" /

Moje tło jest w językach imperatywnych/OO, więc wyjaśnienie, które odnosi się do tego paradygmatu byłoby mile widziane.

Author: BanksySan, 2009-06-22

18 answers

Jeśli chcesz poczuć FRP, możesz zacząć od Starego Fran tutorial z 1998 roku, który ma animowane ilustracje. W przypadku papierów zacznij od funkcjonalna Animacja reaktywna a następnie kontynuuj linki na linku publikacje na mojej stronie głównej i FRP link na Haskell wiki.

Osobiście lubię myśleć o tym, co oznacza FRP , zanim zajmę się tym, jak może być zaimplementowany. (Kod bez specyfikacji jest odpowiedz bez pytania, a więc "nawet źle".) Więc nie opisuję FRP w kategoriach reprezentacji/implementacji, jak to robi Tomasz K w innej odpowiedzi (wykresy, węzły, krawędzie, wypalanie, wykonanie, itp). Istnieje wiele możliwych stylów implementacji, ale żadna implementacja nie mówi, czym jest FRP .

Zgadzam się z prostym opisem Laurence 'a G, że FRP jest o" typach danych, które reprezentują wartość 'w czasie'". Konwencjonalne programowanie imperatywne rejestruje tylko te wartości dynamiczne pośrednio, poprzez stan i mutacje. Kompletna historia (przeszłość, teraźniejszość, przyszłość) nie ma reprezentacji pierwszej klasy. Co więcej, Tylkodyskretnie ewoluujące wartości mogą być (pośrednio) uchwycone, ponieważ imperatywny paradygmat jest czasowo dyskretny. W przeciwieństwie do tego, FRP rejestruje te ewoluujące wartości bezpośrednio i nie ma trudności z w sposób ciągły ewoluujące wartości.

FRP jest również niezwykły, ponieważ jest równoległy bez biegania z teoretycznego & / align = "left" / Semantycznie, współbieżność FRP jest drobnoziarnista, oznaczenie i ciągłe. (Mówię o znaczeniu, nie o implementacji. Implementacja może, ale nie musi, obejmować współbieżność lub równoległość.) Determinacja semantyczna jest bardzo ważna dla rozumowania, zarówno rygorystycznego, jak i nieformalnego. Podczas gdy współbieżność dodaje ogromną złożoność do programowania imperatywnego( ze względu na nieeterministyczne przeplatanie), jest bez wysiłku w FRP.

Czym jest FRP? Mogłeś sam to wymyślić. Zacznij od tych pomysłów:

  • Wartości dynamiczne / ewoluujące (tj. wartości "w czasie") są wartościami pierwszej klasy same w sobie. Możesz je zdefiniować i połączyć, przekazać do funkcji i z nich wyjść. Nazwałem to "zachowaniami".

  • Zachowania są zbudowane z kilku prymitywów, takich jak stałe (statyczne) zachowania i czas (jak zegar), a następnie z sekwencyjną i równoległą kombinacją. N zachowania są łączone przez zastosowanie funkcji n-ary (na wartościach statycznych)," punktowo", tzn. w sposób ciągły w czasie.

  • Aby uwzględnić zjawiska dyskretne, należy mieć inny typ (rodzinę) "zdarzeń", z których każdy ma strumień (skończony lub nieskończony) zdarzeń. Każde wystąpienie ma przypisany czas i wartość.

  • Aby wymyślić słownictwo kompozycyjne, z którego można zbudować wszystkie zachowania i wydarzenia, pobaw się kilkoma przykładami. Zostawić dekonstrukcji na kawałki, które są bardziej ogólne / proste.

  • Aby wiedzieć, że jesteś na solidnym gruncie, daj całemu modelowi podstawę kompozycyjną, używając techniki semantyki denotacyjnej, co oznacza po prostu, że (a) każdy typ ma odpowiedni prosty i precyzyjny matematyczny Typ "znaczeń", oraz (b) każdy prymitywny i operator ma proste i precyzyjne znaczenie jako funkcja znaczeń składników. Nigdy, przenigdy rozważania dotyczące implementacji mix do twojego procesu eksploracji. Jeśli ten opis jest dla Ciebie bełkot, skonsultuj się (a) konstrukcja Denotacyjna z morfizmami klasy typ, (b) Push-pull functional reactive programming (ignorowanie bitów implementacji), oraz (c) semantyka Denotacyjna Haskell wikibooks page. Uważaj, że semantyka denotacyjna ma dwie części, od jej dwóch założycieli Christopher Strachey i Dana Scott: łatwiejsze i bardziej użyteczne część Strachey i trudniejsze i mniej przydatne (do projektowania oprogramowania).

Jeśli będziesz trzymać się tych zasad, spodziewam się, że dostaniesz coś bardziej lub mniej w duchu FRP.

Skąd mam te zasady? W projektowaniu oprogramowania zawsze zadaję to samo pytanie: "co to znaczy?". Semantyka denotacyjna dała mi dokładne ramy dla tego pytania i takie, które pasują do mojej estetyki (w przeciwieństwie do semantyki operacyjnej lub aksjomatycznej, z których obie pozostawiają mnie niezaspokojoną). Więc zapytałem siebie czym jest zachowanie? Wkrótce zdałem sobie sprawę, że czasowa Dyskretna natura obliczeń imperatywnych jest raczej dostosowaniem do określonego stylu maszyny , niż naturalnym opisem samego zachowania. Najprostszy dokładny opis zachowania, jaki przychodzi mi do głowy, to po prostu "funkcja (ciągłego) czasu" , więc taki jest mój model. Model ten z łatwością i wdziękiem radzi sobie z ciągłą, deterministyczną współbieżnością.

Wdrożenie tego modeluj poprawnie i skutecznie, ale to już inna historia.

 930
Author: Conal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-24 18:26:15

W programowaniu funkcjonalnym nie ma żadnych skutków ubocznych. W przypadku wielu rodzajów oprogramowania (na przykład wszystkiego z interakcją z użytkownikiem) efekty uboczne są konieczne na pewnym poziomie.

Jednym ze sposobów na uzyskanie efektu ubocznego, takiego jak zachowanie, przy zachowaniu funkcjonalnego stylu, jest użycie funkcjonalnego programowania reaktywnego. Jest to połączenie programowania funkcyjnego i programowania reaktywnego. (Artykuł Wikipedii, do którego podlinkowałeś, dotyczy tego ostatniego.)

Podstawowa idea reactive programowanie polega na tym, że istnieją pewne typy danych, które reprezentują wartość "w czasie". Obliczenia, które wiążą się z tymi wartościami zmieniającymi się w czasie, same będą miały wartości, które zmieniają się w czasie.

Na przykład, można przedstawić współrzędne myszy jako parę liczb całkowitych w czasie. Powiedzmy, że mieliśmy coś w stylu (to pseudo-kod):

x = <mouse-x>;
y = <mouse-y>;

W dowolnym momencie x i y będą miały współrzędne myszy. W przeciwieństwie do programowania niereaktywnego, musimy tylko to przypisanie raz, a zmienne x i y pozostaną automatycznie "aktualne". Dlatego programowanie reaktywne i programowanie funkcyjne tak dobrze ze sobą współpracują: programowanie reaktywne eliminuje potrzebę mutowania zmiennych, a jednocześnie pozwala wykonać wiele z tego, co można osiągnąć za pomocą mutacji zmiennych.

Jeśli następnie wykonamy pewne obliczenia na tej podstawie, wynikowe wartości będą również wartościami, które zmieniają się w czasie. Na przykład:

minX = x - 16;
minY = y - 16;
maxX = x + 16;
maxY = y + 16;

W tym przykładzie minX będzie zawsze będzie o 16 mniej niż współrzędna x wskaźnika myszy. Z bibliotekami reactive-aware można wtedy powiedzieć coś w stylu:

rectangle(minX, minY, maxX, maxY)

I pole 32x32 zostanie narysowane wokół wskaźnika myszy i będzie śledzić go, gdziekolwiek się porusza.

Oto całkiem dobry artykuł o funkcyjnym programowaniu reaktywnym .

 738
Author: Laurence Gonsalves,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-26 16:45:50

Łatwym sposobem na uzyskanie pierwszej intuicji na temat tego, jak to jest, jest wyobrażenie sobie, że twój program jest arkuszem kalkulacyjnym, a wszystkie Twoje zmienne są komórkami. Jeśli którakolwiek z komórek w arkuszu kalkulacyjnym ulegnie zmianie, Wszystkie komórki, które odnoszą się do tej komórki, również ulegną zmianie. Tak samo jest z FRP. Teraz wyobraź sobie, że niektóre komórki zmieniają się samodzielnie (a raczej są pobierane ze świata zewnętrznego): w sytuacji GUI pozycja myszy byłaby dobrym przykładem.

Że koniecznie brakuje raczej Nr serii Metafora rozkłada się dość szybko, gdy faktycznie używasz systemu FRP. Po pierwsze, zwykle są próby modelowania dyskretnych zdarzeń (np. kliknięcie myszą). Kładę to tutaj, żeby dać ci wyobrażenie, jak to jest.

 144
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-23 14:52:25

Dla mnie chodzi o 2 różne znaczenia symbolu =:

  1. w matematyce x = sin(t) oznacza, że xto inna nazwa dla sin(t). Więc pisanie x + y jest tym samym co sin(t) + y. Funkcjonalne programowanie reaktywne jest pod tym względem jak matematyka: jeśli napiszesz x + y, jest obliczane z dowolną wartością t w momencie jej użycia.
  2. w językach programowania podobnych do C (języki imperatywne), x = sin(t) jest przypisaniem: oznacza to, że x przechowuje wartość z sin(t) zrobione w czasie zadania.
 131
Author: user712092,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-14 17:31:56

OK, z wiedzy i z lektury strony wikipedii, na którą wskazałeś, wynika, że programowanie reaktywne jest czymś w rodzaju przetwarzania danych, ale ze specyficznymi zewnętrznymi "bodźcami" wyzwalającymi zestaw węzłów do odpalania i wykonywania ich obliczeń.

Jest to całkiem dobrze dostosowane do projektowania interfejsu użytkownika, na przykład, w którym dotknięcie kontroli interfejsu użytkownika (powiedzmy, regulacji głośności w aplikacji odtwarzającej muzykę) może wymagać aktualizacji różnych elementów wyświetlania i rzeczywistego głośność wyjścia audio. Gdy modyfikujesz wolumin (powiedzmy suwak), który odpowiadałby modyfikacji wartości powiązanej z węzłem na wykresie skierowanym.

Różne węzły posiadające krawędzie z tego węzła "volume value" zostaną automatycznie wyzwalane, a wszelkie niezbędne obliczenia i aktualizacje naturalnie będą marszczyć przez aplikację. Aplikacja "reaguje" na bodziec użytkownika. Funkcjonalne programowanie reaktywne byłoby tylko realizacją tego pomysłu w funkcjonalnym język, lub ogólnie w ramach paradygmatu programowania funkcyjnego.

Aby dowiedzieć się więcej o "dataflow computing", poszukaj tych dwóch słów na Wikipedii lub użyj ulubionej wyszukiwarki. Ogólna idea jest taka: program jest ukierunkowanym wykresem węzłów, z których każdy wykonuje proste obliczenia. Węzły te są połączone ze sobą za pomocą łączy grafowych, które zapewniają wyjścia niektórych węzłów do wejść innych.

Gdy węzeł zostanie wywołany lub wykona swoje obliczenia, węzły połączone z jego wyjścia mają odpowiednie wejścia "wyzwalane" lub "oznaczone". Każdy węzeł o wszystkich wejściach wyzwalany/oznaczony/dostępny zostanie automatycznie wywołany. Wykres może być niejawny lub jawny w zależności od tego, w jaki sposób implementowane jest programowanie reaktywne.

Węzły mogą być traktowane jako uruchamianie równoległe, ale często są wykonywane seryjnie lub z ograniczoną równoległością(na przykład może być kilka wątków wykonujących je). Słynnym przykładem była Manchester Dataflow Machine, która (IIRC) używała oznakowanej architektury danych do planowania wykonywania węzłów na wykresie za pomocą jednej lub więcej jednostek wykonawczych. Dataflow computing jest dość dobrze przystosowany do sytuacji, w których wyzwalanie obliczeń asynchronicznie powodujące kaskady obliczeń działa lepiej niż próba rządzenia wykonaniem przez zegar (lub zegary).

Reactive programming importuje ten pomysł "kaskady wykonania" i wydaje się myśleć o programie w sposób podobny do przepływu danych, ale z zastrzeżeniem że niektóre z węzłów są podłączone do "świata zewnętrznego" i kaskady wykonania są wyzwalane, gdy te węzły sensoryczne jak zmienić. Wykonanie programu wyglądałoby wtedy jak coś analogicznego do złożonego łuku odruchowego. Program może, ale nie musi, być zasadniczo siedzący między bodźcami lub może osiedlić się w zasadniczo siedzącym stanie między bodźcami.

Programowanie "niereaktywne" byłoby programowaniem z zupełnie innym spojrzeniem na przepływ wykonania i związek z zewnętrznymi wejściami. Prawdopodobnie będzie to nieco subiektywne, ponieważ ludzie prawdopodobnie będą kuszeni, aby powiedzieć cokolwiek, co reaguje na Zewnętrzne wejścia "reaguje" na nich. Ale patrząc na ducha rzeczy, program, który sonduje kolejkę zdarzeń w ustalonym interwale i wysyła wszelkie zdarzenia znalezione dla funkcji (lub wątków) jest mniej reaktywny (ponieważ uczęszcza tylko na dane wejściowe użytkownika w ustalonym interwale). Znowu, to jest duch Rzeczy Tutaj: można sobie wyobrazić wprowadzenie implementacji sondażowej z szybkim interwałem sondażowym w system na bardzo niskim poziomie i program w sposób reaktywny na nim.

 70
Author: Thomas Kammeyer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-24 15:55:53

Po przeczytaniu wielu stron o FRP w końcu natknąłem się nato pouczające pisanie o FRP, w końcu zrozumiałam, o co tak naprawdę chodzi FRP.

Cytuję poniżej Heinricha Apfelmusa (autora reaktywnego banana).

Jaka jest istota funkcjonalnego programowania reaktywnego?

Powszechną odpowiedzią byłoby to ,że " FRP polega na opisywaniu systemu w pojęcia funkcji zmiennych w czasie zamiast stanu zmiennego", i że would na pewno się nie mylę. To jest semantyczny punkt widzenia. Ale w moim zdaniem, im głębsza, bardziej satysfakcjonująca odpowiedź daje po kryterium czysto składniowym:

Istotą funkcjonalnego programowania reaktywnego jest całkowite określenie dynamicznego zachowania wartości w momencie deklaracji.

Na przykład licznik: masz dwa przyciski oznaczone "w górę" i "w dół", które mogą być używane do zwiększania lub zmniejszania licznik. Imperatywnie, najpierw należy podać wartość początkową a potem zmieniaj je za każdym razem, gdy naciśniesz przycisk; coś w tym stylu:

counter := 0                               -- initial value
on buttonUp   = (counter := counter + 1)   -- change it later
on buttonDown = (counter := counter - 1)

Chodzi o to, że w momencie zgłoszenia, tylko wartość początkowa dla licznika jest określony; dynamiczne zachowanie licznika jest ukryte w pozostałej części tekstu programu. Natomiast funkcjonalne programowanie reaktywne określa całe zachowanie dynamiczne w czasie deklaracji, jak to:

counter :: Behavior Int
counter = accumulate ($) 0
            (fmap (+1) eventUp
             `union` fmap (subtract 1) eventDown)

Kiedy tylko chcesz aby zrozumieć dynamikę licznika, wystarczy przyjrzeć się jej definicji. Wszystko, co może mu się przydarzyć, pojawiają się po prawej stronie. Jest to bardzo w przeciwieństwie do imperatywne podejście, w którym kolejne deklaracje mogą zmienić dynamiczne zachowanie wcześniej zadeklarowanych wartości.

Więc wmoje zrozumienie Program FRP jest zbiorem równań: Tutaj wpisz opis obrazka

j jest dyskretna: 1,2,3,4...

f zależy od t więc to zawiera 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, biorąc j do j+1.

Wyjaśniam te równania znacznie bardziej szczegółowo w tym {33]} wideo.

EDIT:

Około 2 lata po pierwotnej odpowiedzi, niedawno doszedłem do wniosku, że implementacje FRP mają inny ważny aspekt. Potrzebują aby (i zazwyczaj) rozwiązać ważny problem praktyczny: unieważnienie pamięci podręcznej.

Równania dla x_i - s opisują wykres zależności. Gdy niektóre x_i zmieniają się w czasie j, nie wszystkie inne x_i' wartości w j+1 muszą być aktualizowane, więc nie wszystkie zależności muszą być przeliczane, ponieważ niektóre x_i' mogą być niezależne od x_i.

Ponadto, x_i - s, które się zmieniają, mogą być stopniowo aktualizowane. Na przykład rozważmy operację mapy f=g.map(_+1) w Scali, gdzie f i gList z Ints. Tutaj f odpowiada x_i(t_j) i g jest x_j(t_j). Teraz, jeśli dodam element do g, to byłoby marnotrawstwem przeprowadzić operację map 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 incremental computing.

Innymi słowy, zachowania (x_i-s ) W FRP mogą być traktowane jako cache-ed obliczenia. Zadaniem silnika FRP jest sprawne unieważnienie i ponowne obliczenie tych Cache-s (x_i - s), jeśli niektóre z f_i-s ulegną zmianie.

 65
Author: jhegedus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-09 04:21:16

The paper Po prostu wydajna reaktywność funkcjonalna by Conal Elliott (direct PDF , 233 KB) jest dość dobrym wstępem. Działa również odpowiednia biblioteka.

Papier jest teraz zastąpiony przez inny papier, Push-pull functional reactive programming (direct PDF, 286 KB).

 29
Author: scvalex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-03 08:35:00

Disclaimer: moja odpowiedź jest w kontekście rx.js - biblioteka "programowania reaktywnego" dla Javascript.

W programowaniu funkcyjnym, zamiast iteracji przez każdy element zbioru, stosuje się funkcje wyższego rzędu (HoFs) do samego zbioru. Tak więc ideą FRP jest to, że zamiast przetwarzać każde pojedyncze zdarzenie, Utwórz strumień zdarzeń (zaimplementowany z obserwowalnym*) i zastosuj do niego Hof. W ten sposób można wizualizować system jako potoki danych łączenie wydawców z subskrybentami.

Główne zalety używania obserwowalnego to:
i) usuwa stan z kodu, np. jeśli chcesz, aby procedura obsługi zdarzeń była wywoływana tylko dla każdego 'n' zdarzenia, lub aby przestała się uruchamiać po pierwszych 'n' zdarzeniach, lub aby zaczęła działać tylko po pierwszych 'n' zdarzeniach, możesz po prostu użyć HoFs (odpowiednio filter, takeUntil, skip) zamiast ustawiać, aktualizować i sprawdzać liczniki.
ii) poprawia lokalizację kodu - jeśli masz 5 różnych procedury obsługi zdarzeń zmieniając stan komponentu, można scalić ich obiekty obserwowalne i zamiast tego zdefiniować pojedynczą procedurę obsługi zdarzeń na scalonym obiekcie obserwowalnym, skutecznie łącząc 5 procedur obsługi zdarzeń w 1. Dzięki temu bardzo łatwo jest zrozumieć, jakie zdarzenia w całym systemie mogą mieć wpływ na komponent, ponieważ wszystko jest obecne w jednym programie obsługi.

  • obserwowalny jest dualny z Iterowalnego.

Iterable to leniwie pochłonięta Sekwencja-każdy element jest ciągnięty przez iterator zawsze, gdy chce z niego korzystać, a zatem wyliczenie jest kierowane przez konsumenta.

Obserwowalny jest leniwie wytwarzaną sekwencją - każdy element jest popychany do obserwatora za każdym razem, gdy jest dodawany do sekwencji, a zatem wyliczenie jest napędzane przez producenta.

 29
Author: tldr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-16 07:04:04

Stary, to genialny pomysł! Dlaczego nie dowiedziałem się o tym w 1998? W każdym razie, oto moja interpretacja Fran tutorial. Sugestie są mile widziane, myślę o uruchomieniu silnika gry na tej podstawie.

import pygame
from pygame.surface import Surface
from pygame.sprite import Sprite, Group
from pygame.locals import *
from time import time as epoch_delta
from math import sin, pi
from copy import copy

pygame.init()
screen = pygame.display.set_mode((600,400))
pygame.display.set_caption('Functional Reactive System Demo')

class Time:
    def __float__(self):
        return epoch_delta()
time = Time()

class Function:
    def __init__(self, var, func, phase = 0., scale = 1., offset = 0.):
        self.var = var
        self.func = func
        self.phase = phase
        self.scale = scale
        self.offset = offset
    def copy(self):
        return copy(self)
    def __float__(self):
        return self.func(float(self.var) + float(self.phase)) * float(self.scale) + float(self.offset)
    def __int__(self):
        return int(float(self))
    def __add__(self, n):
        result = self.copy()
        result.offset += n
        return result
    def __mul__(self, n):
        result = self.copy()
        result.scale += n
        return result
    def __inv__(self):
        result = self.copy()
        result.scale *= -1.
        return result
    def __abs__(self):
        return Function(self, abs)

def FuncTime(func, phase = 0., scale = 1., offset = 0.):
    global time
    return Function(time, func, phase, scale, offset)

def SinTime(phase = 0., scale = 1., offset = 0.):
    return FuncTime(sin, phase, scale, offset)
sin_time = SinTime()

def CosTime(phase = 0., scale = 1., offset = 0.):
    phase += pi / 2.
    return SinTime(phase, scale, offset)
cos_time = CosTime()

class Circle:
    def __init__(self, x, y, radius):
        self.x = x
        self.y = y
        self.radius = radius
    @property
    def size(self):
        return [self.radius * 2] * 2
circle = Circle(
        x = cos_time * 200 + 250,
        y = abs(sin_time) * 200 + 50,
        radius = 50)

class CircleView(Sprite):
    def __init__(self, model, color = (255, 0, 0)):
        Sprite.__init__(self)
        self.color = color
        self.model = model
        self.image = Surface([model.radius * 2] * 2).convert_alpha()
        self.rect = self.image.get_rect()
        pygame.draw.ellipse(self.image, self.color, self.rect)
    def update(self):
        self.rect[:] = int(self.model.x), int(self.model.y), self.model.radius * 2, self.model.radius * 2
circle_view = CircleView(circle)

sprites = Group(circle_view)
running = True
while running:
    for event in pygame.event.get():
        if event.type == QUIT:
            running = False
        if event.type == KEYDOWN and event.key == K_ESCAPE:
            running = False
    screen.fill((0, 0, 0))
    sprites.update()
    sprites.draw(screen)
    pygame.display.flip()
pygame.quit()

W skrócie: jeśli każdy składnik może być traktowany jak liczba, to cały układ może być traktowany jak równanie matematyczne, prawda?

 18
Author: Dan Ross,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-15 17:04:22

Książka Paula Hudaka, Haskell School of Expression , jest nie tylko doskonałym wprowadzeniem do Haskell, ale również spędza sporo czasu na FRP. Jeśli jesteś początkujący z FRP, Gorąco polecam, aby dać poczucie, jak działa FRP.

Jest też coś, co wygląda jak nowy przepis tej książki (wydany 2011, aktualizacja 2014), Haskell School of Music .

 14
Author: cjs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-10 12:31:22

Zgodnie z poprzednimi odpowiedziami, wydaje się, że matematycznie, po prostu myślimy w Wyższej kolejności. Zamiast myśleć o wartości x o typie X , myślimy o funkcji x: TX, Gdzie T jest typem czasu, czy to liczby naturalne, liczby całkowite czy continuum. Teraz kiedy piszemy y := x + 1 w języku programowania mamy na myśli równanie y(t) = x(t ) + 1.

 10
Author: Yuning,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-17 01:09:50

Działa jak arkusz kalkulacyjny, jak wspomniano. Zazwyczaj oparte na frameworku opartym na zdarzeniach.

Jak w przypadku wszystkich "paradygmatów", jego nowość jest dyskusyjna.

Z mojego doświadczenia z rozproszonymi sieciami przepływu aktorów, może łatwo paść ofiarą ogólnego problemu spójności stanów w sieci węzłów, tj. kończy się dużo oscylacji i pułapek w dziwnych pętlach.

Trudno tego uniknąć, ponieważ niektóre semantyki sugerują pętle odniesienia lub nadawanie i mogą być całkiem chaotyczny, gdy sieć aktorów zbiega się (lub nie) na jakimś nieprzewidywalnym stanie.

Podobnie, niektóre stany mogą nie zostać osiągnięte, pomimo dobrze zdefiniowanych krawędzi, ponieważ stan globalny odsuwa się od rozwiązania. 2+2 może być lub nie może być 4 w zależności od tego, kiedy 2 stały się 2 i czy pozostały w ten sposób. Arkusze kalkulacyjne mają synchroniczne zegary i detekcję pętli. Rozproszeni aktorzy na ogół nie.

Dobra zabawa :).

 9
Author: emperorz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-04 11:10:00

Znalazłem ten fajny film na subreddicie Clojure o FRP. Jest to dość łatwe do zrozumienia, nawet jeśli nie znasz Clojure.

Oto film: http://www.youtube.com/watch?v=nket0K1RXU4

Oto źródło, do którego odnosi się film w drugiej połowie: https://github.com/Cicayda/yolk-examples/blob/master/src/yolk_examples/client/autocomplete.cljs

 8
Author: Daniel Kaplan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-17 21:18:26

Ten artykuł autorstwa Andre Staltz jest najlepszym i najjaśniejszym wyjaśnieniem, jakie do tej pory widziałem.

Niektóre cytaty z Artykułu:

Programowanie reaktywne to programowanie za pomocą asynchronicznych strumieni danych.

Ponadto otrzymujesz niesamowity zestaw funkcji do łączenia, tworzenia i filtrowania dowolnego z tych strumieni.

Oto przykład fantastycznych diagramów, które są częścią artykułu:

Kliknij diagram strumienia zdarzeń

 7
Author: GreenGiant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55

Chodzi o matematyczne transformacje danych w czasie (lub ignorowanie czasu).

W kodzie oznacza to czystość funkcjonalną i programowanie deklaratywne.

Błędy stanu są ogromnym problemem w standardowym paradygmacie imperatywu. Różne bity kodu mogą zmieniać niektóre współdzielone stany w różnych "czasach" podczas wykonywania programów. Ciężko sobie z tym poradzić.

W FRP opisujesz (jak w programowaniu deklaratywnym) jak dane zmieniają się z jednego stanu do drugiego i co je uruchamia. Pozwala to na ignorowanie czasu, ponieważ funkcja po prostu reaguje na jego dane wejściowe i używa ich bieżących wartości do tworzenia nowych. Oznacza to, że stan jest zawarty w wykresie (lub drzewie) węzłów transformacji i jest funkcjonalnie czysty.

To znacznie zmniejsza złożoność i czas debugowania.

Pomyśl o różnicy między A = B+C w matematyce a A = B+C w programie. W matematyce opisujesz związek, który nigdy się nie zmieni. W programie, jego mówi, że " prawo teraz " A to B + C. ale następnym poleceniem może być B++, w którym to przypadku A nie jest równe B + C. w matematyce lub programowaniu deklaratywnym A zawsze będzie równe B + C, bez względu na to, o który punkt w czasie zapytasz.

Tak więc poprzez usunięcie złożoności stanu współdzielonego i zmianę wartości w czasie. Twój program jest o wiele łatwiejszy do rozumowania.

Strumień zdarzeń jest strumieniem zdarzeń + pewną funkcją transformacji.

A behavior is a EventStream + Some value in memory.

Gdy zdarzenie zostanie wywołane wartość jest aktualizowana przez uruchomienie funkcji transformacji. Wartość, którą to Wytwarza, jest przechowywana w pamięci zachowań.

Zachowania mogą być tworzone w celu wytworzenia nowych zachowań, które są transformacją na N innych zachowań. Ta złożona wartość zostanie ponownie obliczona, gdy wywołane zostaną zdarzenia wejściowe (zachowania).

" ponieważ obserwatorzy są bezstanowi, często potrzebujemy kilku z nich, aby symulować maszynę stanową, jak w przykładzie drag. Musimy zapisać stan, w którym jest on dostępny dla wszystkich zaangażowane obserwatorów, takich jak w zmiennej ścieżki powyżej."

Cytat z-Deprecating The Observer Pattern http://infoscience.epfl.ch/record/148043/files/DeprecatingObserversTR2010.pdf

 5
Author: Jay Shepherd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-16 04:15:12

Krótkie i jasne wyjaśnienie dotyczące programowania reaktywnego pojawia się na Cyclejs-Programowanie reaktywne, wykorzystuje proste i wizualne próbki.

A [moduł / komponent/obiekt] jest reaktywny oznacza, że jest w pełni odpowiedzialny do zarządzania własnym stanem poprzez reagowanie na zdarzenia zewnętrzne.

Jakie są korzyści z takiego podejścia? Jest to Inwersja Sterowania , głównie dlatego, że [moduł / komponent/obiekt] jest odpowiedzialny za siebie, poprawiając enkapsulacji przy użyciu metod prywatnych przeciwko metodom publicznym.

To dobry punkt startowy, a nie kompletne źródło wiedzy. Stamtąd można przejść do bardziej złożonych i głębokich dokumentów.

 2
Author: pdorgambide,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-05 10:21:32

Sprawdź RX, Reactive Extensions for. NET. zwracają uwagę, że z IEnumerable w zasadzie 'wyciągasz' ze strumienia. Zapytania Linq nad IQueryable / IEnumerable są operacjami ustawionymi, które "wysysają" wyniki z zestawu. Ale z tymi samymi operatorami nad IObservable możesz pisać zapytania Linq, które 'reagują'.

Na przykład, możesz napisać zapytanie Linq jak (od m w MyObservableSetOfMouseMovements gdzie m. X

I z Rx rozszerzenia, to wszystko: masz kod interfejsu użytkownika, który reaguje na przychodzący strumień ruchów myszy i rysuje, gdy jesteś w polu 100,100...

 0
Author: Sentinel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-25 15:59:58

FRP jest połączeniem programowania funkcyjnego (paradygmat programowania zbudowany na idei, że wszystko jest funkcją) i paradygmatu programowania reaktywnego (opartego na idei, że wszystko jest strumieniem (filozofia obserwatora i obserwowalna)). To ma być najlepszy ze światów.

Sprawdź post Andre Staltz na temat programowania reaktywnego na początek.

 0
Author: Krishna Ganeriwal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-10 13:03:47