rxjava react programming español applications javascript haskell functional-programming reactive-programming frp

react - ¿Cómo implementar el tipo de comportamiento FRP de Haskell en Javascript?



rx react (1)

Su implementación de behavior está más cerca de los eventos en la terminología de FRP, aunque los eventos de FRP y los eventos de DOM no tienen nada en común. En su núcleo, FRP abstrae la noción de tiempo continuo (en lugar de discreto). Behavior a representa un flujo continuo de valores de tipo a ; por lo tanto, su significado es como una función del tiempo al valor.

Es literalmente como lo definió Conal Eliott:

μ :: Behaviour a -> (Time -> a)

Esa notación es la que él usó para describir el significado de algo como una función de eso a un valor computacional concreto.

Los eventos son "comportamientos congelados en el tiempo", es decir, representan valores que ocurrieron en momentos específicos:

μ :: Event a -> [(Time, a)]

Debido a que Haskell es un lenguaje perezoso, los flujos de valores pueden representarse como listas, que es lo que dice lo anterior.

Por extraño que parezca, no hay muchas implementaciones de FRP que permanezcan fieles a la idea original, ya que (creo) es difícil encontrar una realización eficaz del tiempo continuo: este C ++ parece acercarse .

Te animo a que veas las charlas de Conal Eliott disponibles en línea, son algunos de los diseños de API más elegantes que he visto y lo explica con claridad.

Me gustaría entender el significado original de la programación reactiva funcional en Haskell y en qué se diferencia de la aplicación real de FRP en Javascript. Desafortunadamente, solo tengo una comprensión superficial de Haskell y tengo que seguir usando Javascript.

Aquí está mi intento de implementar el tipo de datos de Behavior de Haskell en un lenguaje sin tipo:

// behavior :: String -> DOMHTMLElement -> a -> (a -> Event -> a) -> (a -> b) const behavior = type => target => x => f => { const destructiveSet = y => (x = f(x) (y), x), // A handler = event => destructiveSet(event); target.addEventListener(type, handler, true); return g => g(x); };

La línea A es necesaria, porque tengo que mutar el valor inicial x , que se mantiene en la pila de llamadas. El cuerpo de la función evalúa de izquierda a derecha y devuelve el valor del último operando del operador de coma, es decir, la versión actualizada de forma destructiva de x .

target.addEventListener simplemente suscribe el controlador dado al elemento HTML DOM dado.

behavior devuelve una función que permite el acceso de solo lectura a x .

Esta implementación introduce un tipo de datos abstractos de solo lectura en Javascript, cuyos valores solo existen en las pilas de llamadas de las funciones de orden superior. Siempre que los eventos de DOM solo sean activados por usuarios de GUI, un programa no tiene medios para mutar los valores del behavior de tipo. Solo puede encuestarlos para observar el efecto que varía con el tiempo.

¿Es este enfoque remotamente comparable al Behavior de Haskell?

Aquí hay un pequeño ejemplo: un contador de clics del mouse (cuenta por cuatro segundos):

const behavior = type => target => x => f => { const destructiveSet = y => (x = f(x) (y), x), handler = event => destructiveSet(event); target.addEventListener(type, handler, true); return g => g(x); }; const comp = f => g => x => f(g(x)); const K = x => y => x; const I = x => x; const get = I; const defer = n => f => x => setTimeout(f, n, x); const log = prefix => x => console.log(prefix, x); const inc = x => x + 1; const counter = behavior("click") (document) (0) (comp(K) (inc)); console.log("click on the section above"); counter(get); // 0 defer(4000) (counter) (log("counted clicks:"));