ventajas rxjava reactivas reactiva que programming programacion libro funcional desventajas aplicaciones functional-programming terminology reactive-programming frp

functional-programming - rxjava - reactive programming



¿Qué es la programación reactiva(funcional)? (18)

He leído el artículo de Wikipedia sobre programación reactiva . También he leído el pequeño artículo sobre programación reactiva funcional . Las descripciones son bastante abstractas.

  1. ¿Qué significa en la práctica la programación reactiva funcional (FRP)?
  2. ¿En qué consiste la programación reactiva (a diferencia de la programación no reactiva)?

Mi experiencia es en idiomas imperativos / OO, por lo que se agradecería una explicación relacionada con este paradigma.


Actúa como una hoja de cálculo como se señala. Generalmente se basa en un marco impulsado por eventos.

Como con todos los "paradigmas", su novedad es discutible.

Desde mi experiencia en redes de flujo distribuido de actores, puede fácilmente ser presa de un problema general de consistencia de estado en la red de nodos, es decir, termina con una gran cantidad de oscilaciones y trampas en bucles extraños.

Esto es difícil de evitar ya que algunas semánticas implican bucles referenciales o transmisiones, y pueden ser bastante caóticas a medida que la red de actores converge (o no) en algún estado impredecible.

De manera similar, algunos estados pueden no alcanzarse, a pesar de tener bordes bien definidos, porque el estado global se aleja de la solución. 2 + 2 puede o no llegar a ser 4 dependiendo de cuándo los 2 se convirtieron en 2, y si se mantuvieron así. Las hojas de cálculo tienen relojes síncronos y detección de bucles. Los actores distribuidos generalmente no lo hacen.

Todo muy divertido :).


Amigo, ¡esta es una idea genial! ¿Por qué no me enteré de esto en 1998? De todos modos, aquí está mi interpretación del tutorial de Fran . Las sugerencias son bienvenidas, estoy pensando en iniciar un motor de juego basado en esto.

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()

En resumen: si cada componente se puede tratar como un número, todo el sistema se puede tratar como una ecuación matemática, ¿verdad?


Bien, de los conocimientos previos y de la lectura de la página de Wikipedia a la que señala, parece que la programación reactiva es algo así como la computación de flujo de datos pero con "estímulos" externos específicos que activan un conjunto de nodos para disparar y realizar sus cálculos.

Esto se adapta bastante bien al diseño de la interfaz de usuario, por ejemplo, en el que tocar un control de interfaz de usuario (por ejemplo, el control de volumen en una aplicación de reproducción de música) podría necesitar actualizar varios elementos de la pantalla y el volumen real de la salida de audio. Cuando modifica el volumen (un control deslizante, digamos) que correspondería a modificar el valor asociado con un nodo en un gráfico dirigido.

Varios nodos que tienen bordes de ese nodo de "valor de volumen" se activarán automáticamente y cualquier cálculo y actualización necesarios naturalmente se interpondrán en la aplicación. La aplicación "reacciona" al estímulo del usuario. La programación reactiva funcional sería solo la implementación de esta idea en un lenguaje funcional, o generalmente dentro de un paradigma de programación funcional.

Para obtener más información sobre "computación de flujo de datos", busque esas dos palabras en Wikipedia o use su motor de búsqueda favorito. La idea general es esta: el programa es un gráfico dirigido de nodos, cada uno de los cuales realiza algunos cálculos simples. Estos nodos están conectados entre sí por enlaces de gráficos que proporcionan las salidas de algunos nodos a las entradas de otros.

Cuando un nodo se dispara o realiza su cálculo, los nodos conectados a sus salidas tienen sus entradas correspondientes "activadas" o "marcadas". Cualquier nodo que tenga todas las entradas activadas / marcadas / disponibles se activará automáticamente. El gráfico puede ser implícito o explícito dependiendo de exactamente cómo se implementa la programación reactiva.

Se puede considerar que los nodos se disparan en paralelo, pero a menudo se ejecutan en serie o con un paralelismo limitado (por ejemplo, puede haber algunos hilos ejecutándolos). Un ejemplo famoso fue la Máquina de flujo de datos de Manchester , que (IIRC) usó una arquitectura de datos etiquetada para programar la ejecución de nodos en el gráfico a través de una o más unidades de ejecución. La computación de flujo de datos se adapta bastante bien a situaciones en las que los cálculos de activación asincrónica que dan lugar a cascadas de cálculos funcionan mejor que tratar de que la ejecución se rija por un reloj (o relojes).

La programación reactiva importa esta idea de "cascada de ejecución" y parece pensar en el programa de manera similar a un flujo de datos, pero con la condición de que algunos de los nodos se enganchan al "mundo exterior" y las cascadas de ejecución se activan cuando estos sensores sensoriales -Como los nodos cambian. La ejecución del programa se vería entonces como algo análogo a un arco reflejo complejo. El programa puede o no ser básicamente sésil entre estímulos o puede establecerse en un estado básicamente sésil entre estímulos.

La programación "no reactiva" sería la programación con una visión muy diferente del flujo de ejecución y la relación con las entradas externas. Es probable que sea algo subjetivo, ya que las personas probablemente se verán tentadas a decir que cualquier cosa que responda a entradas externas "reacciona" ante ellas. Pero al observar el espíritu de la cosa, un programa que sondea una cola de eventos en un intervalo fijo y envía los eventos encontrados a las funciones (o subprocesos) es menos reactivo (porque solo atiende a las entradas del usuario en un intervalo fijo). Una vez más, es el espíritu de la cosa aquí: uno puede imaginar poner una implementación de sondeo con un intervalo de sondeo rápido en un sistema a un nivel muy bajo y programar de manera reactiva encima de él.


De acuerdo con las respuestas anteriores, parece que matemáticamente, simplemente pensamos en un orden superior. En lugar de pensar que un valor x tiene el tipo X , pensamos en una función x : TX , donde T es el tipo de tiempo, ya sean los números naturales, los enteros o el continuo. Ahora, cuando escribimos y : = x + 1 en el lenguaje de programación, nos referimos a la ecuación y ( t ) = x ( t ) + 1.


Descargo de responsabilidad: mi respuesta está en el contexto de rx.js - una biblioteca de ''programación reactiva'' para Javascript.

En la programación funcional, en lugar de iterar a través de cada elemento de una colección, se aplican funciones de orden superior (HoF) a la propia colección. Entonces, la idea detrás de FRP es que, en lugar de procesar cada evento individual, cree un flujo de eventos (implementado con un observable *) y aplique HoF a eso. De esta manera, puede visualizar el sistema como líneas de datos que conectan a los editores con los suscriptores.

Las principales ventajas de usar un observable son:
i) se abstrae del estado de su código, por ejemplo, si desea que el controlador de eventos se active solo para cada ''n'' evento, o que deje de activarse después de los primeros ''n'' eventos, o que comience a activarse solo después de los primeros ''n En los eventos, puede usar HoFs (filter, takeUntil, skip respectivamente) en lugar de configurar, actualizar y verificar los contadores.
ii) mejora la localidad del código: si tiene 5 controladores de eventos diferentes que cambian el estado de un componente, puede combinar sus observables y definir un solo controlador de eventos en el observable combinado, combinando efectivamente 5 controladores de eventos en 1. Esto lo hace muy fácil de razonar sobre qué eventos en todo su sistema pueden afectar a un componente, ya que todos están presentes en un solo controlador.

  • Un observable es el dual de un iterable.

Un iterable es una secuencia que se consume de manera perezosa: cada iterador es arrastrado por el elemento cada vez que quiere usarlo, y por lo tanto, la enumeración es manejada por el consumidor.

Un observable es una secuencia producida de forma perezosa: cada elemento se envía al observador cada vez que se agrega a la secuencia y, por lo tanto, la enumeración es dirigida por el productor.


Después de leer muchas páginas sobre FRP, finalmente encontré this esclarecedor escrito sobre FRP, finalmente me hizo entender de qué se trata realmente FRP.

Cito a continuación Heinrich Apfelmus (autor de banana reactiva).

¿Cuál es la esencia de la programación reactiva funcional?

Una respuesta común sería que "FRP se trata de describir un sistema en términos de funciones que varían en el tiempo en lugar de un estado mutable", y eso ciertamente no sería incorrecto. Este es el punto de vista semántico. Pero en mi opinión, la respuesta más profunda y satisfactoria está dada por el siguiente criterio puramente sintáctico:

La esencia de la programación reactiva funcional es especificar el comportamiento dinámico de un valor completamente en el momento de la declaración.

Por ejemplo, tome el ejemplo de un contador: tiene dos botones etiquetados "Arriba" y "Abajo" que se pueden usar para aumentar o disminuir el contador. De manera imperativa, primero debe especificar un valor inicial y luego cambiarlo cada vez que se presiona un botón; algo como esto:

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

El punto es que en el momento de la declaración, solo se especifica el valor inicial para el contador; El comportamiento dinámico del contador está implícito en el resto del texto del programa. En contraste, la programación reactiva funcional especifica todo el comportamiento dinámico en el momento de la declaración, como esto:

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

Cuando quiera comprender la dinámica del contador, solo tiene que ver su definición. Todo lo que pueda suceder aparecerá en el lado derecho. Esto contrasta con el enfoque imperativo en el que las declaraciones posteriores pueden cambiar el comportamiento dinámico de los valores declarados anteriormente.

Por lo tanto, a mi entender, un programa de FRP es un conjunto de ecuaciones:

j es discreto: 1,2,3,4 ...

f depende de t por lo que esto incorpora la posibilidad de modelar estímulos externos

Todo el estado del programa está encapsulado en las variables x_i

La biblioteca de FRP se ocupa del tiempo en progreso, en otras palabras, tomando j to j+1 .

Explico estas ecuaciones con mucho más detalle en this video.

EDITAR:

Aproximadamente 2 años después de la respuesta original, recientemente llegué a la conclusión de que las implementaciones de FRP tienen otro aspecto importante. Necesitan (y generalmente lo hacen) resolver un problema práctico importante: la invalidación de caché .

Las ecuaciones para x_i -s describen un gráfico de dependencia. Cuando algunos de los cambios de x_i cambian en el momento j entonces no es necesario actualizar todos los demás valores de x_i'' en j+1 , por lo que no es necesario volver a calcular todas las dependencias porque algunos x_i'' pueden ser independientes de x_i .

Además, x_i -s que sí cambian pueden actualizarse incrementalmente. Por ejemplo, consideremos una operación de mapa f=g.map(_+1) en Scala, donde f y g son List de Ints . Aquí f corresponde a x_i(t_j) g es x_j(t_j) . Ahora, si antepongo un elemento a g , sería un desperdicio realizar la operación de map para todos los elementos en g . Algunas implementaciones de FRP (por ejemplo, reflex-frp ) buscan resolver este problema. Este problema también se conoce como computación incremental.

En otras palabras, los comportamientos (los x_i -s) en FRP se pueden pensar como cálculos en memoria caché. La tarea del motor de FRP es invalidar y volver a calcular estos cache-s (los x_i -s) de manera eficiente si algunos de los f_i -s cambian.


Echa un vistazo a Rx, Extensiones reactivas para .NET. Señalan que con IEnumerable básicamente estás "tirando" de una transmisión. Las consultas de Linq sobre IQueryable / IEnumerable son operaciones de conjuntos que "succionan" los resultados de un conjunto. Pero con los mismos operadores a través de IObservable puede escribir consultas Linq que "reaccionen".

Por ejemplo, podría escribir una consulta de Linq como (desde m en MyObservableSetOfMouseMovements donde mX <100 y mY <100 seleccionan un nuevo punto (mX, mY)).

y con las extensiones Rx, eso es todo: tienes un código de UI que reacciona a la corriente entrante de movimientos y dibujados del mouse cuando estás en el cuadro 100,100 ...


El libro de Paul Hudak, The Haskell School of Expression , no solo es una buena introducción a Haskell, sino que también dedica una buena cantidad de tiempo a FRP. Si usted es un principiante con FRP, lo recomiendo para que le dé una idea de cómo funciona FRP.

También hay lo que parece una nueva versión de este libro (publicado en 2011, actualizado en 2014), The Haskell School of Music .



En la programación funcional pura, no hay efectos secundarios. Para muchos tipos de software (por ejemplo, cualquier cosa con interacción del usuario) los efectos secundarios son necesarios en algún nivel.

Una forma de obtener efectos secundarios similares a los efectos secundarios mientras se mantiene un estilo funcional es usar la programación reactiva funcional. Esta es la combinación de programación funcional y programación reactiva. (El artículo de Wikipedia al que has vinculado trata sobre este último).

La idea básica detrás de la programación reactiva es que hay ciertos tipos de datos que representan un valor "en el tiempo". Los cálculos que involucran estos valores de cambio en el tiempo tendrán valores que cambiarán con el tiempo.

Por ejemplo, podría representar las coordenadas del mouse como un par de valores de enteros sobre el tiempo. Digamos que tuvimos algo como (esto es pseudo-código):

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

En cualquier momento en el tiempo, x e y tendrían las coordenadas del mouse. A diferencia de la programación no reactiva, solo necesitamos hacer esta asignación una vez, y las variables x e y permanecerán "actualizadas" automáticamente. Esta es la razón por la que la programación reactiva y la programación funcional funcionan tan bien juntas: la programación reactiva elimina la necesidad de mutar las variables y, al mismo tiempo, le permite hacer mucho de lo que podría lograr con las mutaciones variables.

Si luego hacemos algunos cálculos basados ​​en esto, los valores resultantes también serán valores que cambiarán con el tiempo. Por ejemplo:

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

En este ejemplo, minX siempre será 16 menos que la coordenada x del puntero del mouse. Con bibliotecas reactivas, podría decir algo como:

rectangle(minX, minY, maxX, maxY)

Y se dibujará un cuadro de 32x32 alrededor del puntero del mouse y lo rastreará donde sea que se mueva.

Aquí hay un buen artículo sobre programación reactiva funcional .



FRP es una combinación de programación funcional (paradigma de programación basado en la idea de todo es una función) y paradigma de programación reactiva (basado en la idea de que todo es una corriente (filosofía observadora y observable)). Se supone que es lo mejor de los mundos.

Echa un vistazo a la publicación de Andre Staltz sobre programación reactiva para comenzar.


La explicación breve y clara sobre la programación reactiva aparece en Cyclejs - Programación reactiva , utiliza muestras simples y visuales.

Un [módulo / Componente / objeto] es reactivo significa que es totalmente responsable de administrar su propio estado al reaccionar ante eventos externos.

¿Cuál es el beneficio de este enfoque? Es Inversión de control , principalmente porque [módulo / Componente / objeto] es responsable de sí mismo, mejorando la encapsulación utilizando métodos privados en contra de los públicos.

Es un buen punto de inicio, no una fuente completa de conocimiento. Desde allí podrás saltar a papeles más complejos y profundos.


Para mí se trata de 2 significados diferentes de símbolo = :

  1. En matemáticas, x = sin(t) significa que x es un nombre diferente para sin(t) . Entonces escribir x + y es lo mismo que sin(t) + y . La programación reactiva funcional es como la matemática a este respecto: si escribes x + y , se calcula con el valor de t en el momento en que se usa.
  2. En los lenguajes de programación tipo C (lenguajes imperativos), x = sin(t) es una asignación: significa que x almacena el valor de sin(t) tomado en el momento de la asignación.

Se trata de transformaciones de datos matemáticos en el tiempo (o ignorar el tiempo).

En código esto significa pureza funcional y programación declarativa.

Los errores estatales son un gran problema en el paradigma imperativo estándar. Varios bits de código pueden cambiar algún estado compartido en diferentes "tiempos" en la ejecución de los programas. Esto es difícil de tratar.

En FRP, usted describe (como en la programación declarativa) cómo los datos se transforman de un estado a otro y qué los desencadena. Esto le permite ignorar el tiempo porque su función simplemente reacciona a sus entradas y utiliza sus valores actuales para crear una nueva. Esto significa que el estado está contenido en el gráfico (o árbol) de los nodos de transformación y es funcionalmente puro.

Esto reduce enormemente la complejidad y el tiempo de depuración.

Piense en la diferencia entre A = B + C en matemáticas y A = B + C en un programa. En matemáticas estás describiendo una relación que nunca cambiará. En un programa, se dice que "En este momento" A es B + C. Pero el siguiente comando podría ser B ++ en cuyo caso A no es igual a B + C. En matemáticas o programación declarativa, A siempre será igual a B + C, sin importar el momento en el que pregunte.

Así, eliminando las complejidades del estado compartido y cambiando los valores a lo largo del tiempo. Tu programa es mucho más fácil de razonar.

Un EventStream es un EventStream + alguna función de transformación.

Un comportamiento es un EventStream + Algunos valores en la memoria.

Cuando el evento se dispara, el valor se actualiza ejecutando la función de transformación. El valor que esto produce se almacena en la memoria de comportamientos.

Los comportamientos se pueden componer para producir nuevos comportamientos que son una transformación en N otros comportamientos. Este valor compuesto se recalculará a medida que se activen los eventos de entrada (comportamientos).

"Dado que los observadores son apátridas, a menudo necesitamos varios de ellos para simular una máquina de estados como en el ejemplo de arrastre. Tenemos que guardar el estado donde todos los observadores involucrados puedan acceder a ella, como en la ruta de variables anterior".

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


Si desea familiarizarse con el FRP, puede comenzar con el antiguo tutorial de Fran de 1998, que contiene ilustraciones animadas. Para artículos, comience con la Animación reactiva funcional y luego haga un seguimiento de los enlaces en el enlace de publicaciones en mi página de inicio y el enlace de FRP en la wiki de Haskell .

Personalmente, me gusta pensar qué significa FRP antes de abordar cómo podría implementarse. (El código sin una especificación es una respuesta sin pregunta y, por lo tanto, "ni siquiera es incorrecto".) Por lo tanto, no describo FRP en términos de representación / implementación como Thomas K lo hace en otra respuesta (gráficos, nodos, bordes, disparo, ejecución, etc). Hay muchos estilos de implementación posibles, pero ninguna implementación dice lo que es FRP.

Resueno con la simple descripción de Laurence G de que FRP se trata de "tipos de datos que representan un valor ''en el tiempo''". La programación imperativa convencional captura estos valores dinámicos solo de manera indirecta, a través del estado y las mutaciones. La historia completa (pasado, presente, futuro) no tiene representación de primera clase. Además, solo los valores que evolucionan discretamente se pueden capturar (indirectamente), ya que el paradigma imperativo es temporalmente discreto. En contraste, FRP captura estos valores en evolución directamente y no tiene dificultad con los valores en constante evolución.

FRP también es inusual, ya que es concurrente sin chocar con el nido de ratas teórico y pragmático que plaga la concurrencia imperativa. Semánticamente, la concurrencia de FRP es de grano fino , determinada y continua . (Estoy hablando de significado, no de implementación. Una implementación puede o no involucrar concurrencia o paralelismo.) La determinación semántica es muy importante para el razonamiento, tanto riguroso como informal. Si bien la concurrencia agrega una complejidad enorme a la programación imperativa (debido al intercalado no determinista), es fácil en el FRP.

Entonces, ¿qué es FRP? Podrías haberlo inventado tú mismo. Comience con estas ideas:

  • Los valores dinámicos / en evolución (es decir, los valores "a lo largo del tiempo") son valores de primera clase en sí mismos. Puede definirlos y combinarlos, pasarlos dentro y fuera de las funciones. Llamé a estas cosas "comportamientos".

  • Los comportamientos se construyen a partir de algunas primitivas, como los comportamientos constantes (estáticos) y el tiempo (como un reloj), y luego con una combinación secuencial y paralela. Los comportamientos n se combinan aplicando una función n-aria (en valores estáticos), "puntuales", es decir, continuamente a lo largo del tiempo.

  • Para tener en cuenta los fenómenos discretos, tenga otro tipo (familia) de "eventos", cada uno de los cuales tiene una secuencia (finita o infinita) de ocurrencias. Cada ocurrencia tiene un tiempo y un valor asociado.

  • Para crear el vocabulario compositivo a partir del cual se pueden construir todos los comportamientos y eventos, juegue con algunos ejemplos. Sigue deconstruyendo en piezas que sean más generales / simples.

  • Para que sepa que está en una base sólida, otorgue a todo el modelo una base compositiva, utilizando la técnica de semántica denotacional, lo que significa que (a) cada tipo tiene un tipo matemático simple y preciso correspondiente de "significados", y ( b) cada primitivo y operador tiene un significado simple y preciso en función de los significados de los constituyentes. Nunca, nunca mezcle las consideraciones de implementación en su proceso de exploración. Si esta descripción le resulta incomprensible, consulte (a) Diseño denotacional con morfismos de clase de tipo , (b) Programación reactiva funcional push-pull (ignorando los bits de implementación), y (c) Página de wikibooks de semántica denotacional de Haskell . Tenga en cuenta que la semántica de denotación tiene dos partes, de sus dos fundadores Christopher Strachey y Dana Scott: la parte de Strachey más fácil y más útil y la parte de Scott más difícil y menos útil (para el diseño de software).

Si sigue estos principios, espero que obtenga algo más o menos en el espíritu de FRP.

¿De dónde obtuve estos principios? En el diseño de software, siempre hago la misma pregunta: "¿qué significa?". La semántica denotacional me dio un marco preciso para esta pregunta, y uno que se adapta a mi estética (a diferencia de la semántica operacional o axiomática, que me dejan insatisfecho). Entonces me pregunté qué es el comportamiento? Pronto me di cuenta de que la naturaleza temporal discreta de la computación imperativa es una adaptación a un estilo particular de máquina , en lugar de una descripción natural del comportamiento en sí. La descripción precisa más simple del comportamiento que puedo pensar es simplemente "función del tiempo (continuo)", así que ese es mi modelo. Encantadoramente, este modelo maneja la concurrencia determinista y continua con facilidad y gracia.

Ha sido todo un reto implementar este modelo de manera correcta y eficiente, pero esa es otra historia.


Una forma fácil de llegar a una primera intuición acerca de cómo es imaginar que su programa es una hoja de cálculo y todas sus variables son celdas. Si alguna de las celdas en una hoja de cálculo cambia, cualquier celda que se refiera a esa celda también cambiará. Es lo mismo con FRP. Ahora imagine que algunas de las celdas cambian por sí mismas (o más bien, se toman del mundo exterior): en una situación de GUI, la posición del mouse sería un buen ejemplo.

Eso necesariamente se pierde bastante mucho. La metáfora se rompe bastante rápido cuando realmente usas un sistema de FRP. Por un lado, generalmente también hay intentos de modelar eventos discretos (por ejemplo, al hacer clic en el mouse). Solo estoy poniendo esto aquí para darte una idea de cómo es.


Este artículo de Andre Staltz es la mejor y más clara explicación que he visto hasta ahora.

Algunas citas del artículo:

La programación reactiva es la programación con flujos de datos asíncronos.

Además de eso, te dan una increíble caja de herramientas con funciones para combinar, crear y filtrar cualquiera de esas secuencias.

Aquí hay un ejemplo de los fantásticos diagramas que forman parte del artículo: