Quel est le statut des implémentations actuelles de la programmation fonctionnelle réactive?


90

J'essaie de visualiser quelques systèmes physiques automatiques simples (tels que le pendule, les bras de robot, etc.) dans Haskell. Souvent, ces systèmes peuvent être décrits par des équations comme

df/dt = c*f(t) + u(t)

u(t)représente une sorte de «contrôle intelligent». Ces systèmes semblent s'intégrer très bien dans le paradigme de la programmation réactive fonctionnelle.

J'ai donc attrapé le livre "The Haskell School of Expression" de Paul Hudak, et j'ai trouvé que le langage spécifique au domaine "FAL" (pour Functional Animation Language) présenté ici fonctionne en fait assez bien pour mes systèmes de jouets simples (bien que certaines fonctions, notamment integrate, semblait un peu trop paresseux pour une utilisation efficace, mais facilement réparable).

Ma question est la suivante: quelle est l'alternative la plus mature, à jour, bien entretenue et optimisée pour les applications plus avancées ou même pratiques aujourd'hui?

Cette page wiki répertorie plusieurs options pour Haskell, mais je ne suis pas clair sur les points suivants:

  1. Le statut de «réactif», le projet de Conal Eliott qui est (si je comprends bien) l'un des inventeurs de ce paradigme de programmation, semble un peu dépassé. J'adore son code, mais je devrais peut-être essayer d'autres alternatives plus récentes? Quelle est la principale différence entre eux, en termes de syntaxe / performances / stabilité à l'exécution?

  2. Pour citer une enquête de 2011, section 6, " ... les implémentations de FRP ne sont toujours pas suffisamment efficaces ou suffisamment prévisibles en termes de performances pour être utilisées efficacement dans des domaines qui nécessitent des garanties de latence ... ". Bien que l'enquête suggère quelques optimisations possibles intéressantes, étant donné que FRP est là depuis plus de 15 ans, j'ai l'impression que ce problème de performance pourrait être quelque chose de très ou même intrinsèquement difficile à résoudre au moins dans quelques années. Est-ce vrai?

  3. Le même auteur de l'enquête évoque les "fuites de temps" dans son blog . Le problème est-il propre à FRP, ou quelque chose que nous rencontrons généralement lors de la programmation dans un langage pur et non strict? Avez-vous déjà trouvé trop difficile de stabiliser un système à base de FRP au fil du temps, sinon assez performant?

  4. Est-ce toujours un projet de niveau recherche? Les gens comme les ingénieurs d'usine, les ingénieurs en robotique, les ingénieurs financiers, etc. les utilisent-ils réellement (dans le langage qui correspond à leurs besoins)?

Bien que je préfère personnellement une implémentation Haskell, je suis ouvert à d'autres suggestions. Par exemple, il serait particulièrement amusant d'avoir une implémentation Erlang - il serait alors très facile d'avoir un processus serveur intelligent, adaptatif et auto-apprenant!

Réponses:


82

À l'heure actuelle, il existe principalement deux bibliothèques Haskell pratiques pour la programmation réactive fonctionnelle. Les deux sont gérés par des personnes seules, mais reçoivent également des contributions de code d'autres programmeurs Haskell:

  • Netwire se concentre sur l'efficacité, la flexibilité et la prévisibilité. Il a son propre paradigme d'événement et peut être utilisé dans les zones où le FRP traditionnel ne fonctionne pas, y compris les services réseau et les simulations complexes. Style: applicatif et / ou fléché. Auteur initial et mainteneur: Ertugrul Söylemez (c'est moi).

  • reactive-banana s'appuie sur le paradigme traditionnel du PRF. Bien qu'il soit pratique à utiliser, il sert également de base à la recherche classique sur les FRP. Son objectif principal est les interfaces utilisateur et il existe une interface prête à l'emploi pour wx. Style: applicatif. Auteur initial et mainteneur: Heinrich Apfelmus.

Vous devriez essayer les deux, mais en fonction de votre application, vous trouverez probablement l'un ou l'autre plus adapté.

Pour les jeux, le réseautage, le contrôle de robot et les simulations, vous trouverez Netwire utile. Il est livré avec des fils prêts à l'emploi pour ces applications, y compris divers différentiels utiles, intégrales et de nombreuses fonctionnalités pour une gestion transparente des événements. Pour un tutoriel, visitez la documentation duControl.Wire module sur la page que j'ai liée.

Pour les interfaces utilisateur graphiques actuellement, votre meilleur choix est réactif-banane. Il a déjà une interface wx (en tant que bibliothèque séparée reactive-banana-wx) et Heinrich parle beaucoup de FRP dans ce contexte, y compris des exemples de code.

Pour répondre à vos autres questions: FRP ne convient pas dans les scénarios où vous avez besoin d'une prévisibilité en temps réel. Ceci est en grande partie dû à Haskell, mais malheureusement FRP est difficile à réaliser dans les langues de niveau inférieur. Dès que Haskell lui-même sera prêt en temps réel, FRP y arrivera également. Conceptuellement, Netwire est prêt pour les applications en temps réel.

Les fuites de temps ne sont plus vraiment un problème, car elles sont largement liées au cadre monadique. Les implémentations pratiques de FRP n'offrent tout simplement pas une interface monadique. Yampa a commencé cela et Netwire et reactive-banana s'appuient tous deux sur cela.

Je ne connais actuellement aucun projet commercial ou à grande échelle utilisant le FRP. Les bibliothèques sont prêtes, mais je pense que les gens ne le sont pas encore.


Excellente réponse, merci ... ce sera un exercice amusant d'implémenter des algorithmes d'apprentissage par renforcement au-dessus de votre bibliothèque.
mnish

3
Notamment, un jeu indépendant récent écrit en Haskell ( Nikki and the Robots ) a pris la décision de ne pas utiliser FRP.
Alex R

23

Bien qu'il y ait déjà de bonnes réponses, je vais tenter de répondre à vos questions spécifiques.

  1. réactif n'est pas utilisable pour des projets sérieux, en raison de problèmes de fuite de temps. (voir # 3). La bibliothèque actuelle avec le design le plus similaire est reactive-banana, qui a été développée avec réactif comme inspiration, et en discussion avec Conal Elliott.

  2. Bien que Haskell lui-même ne soit pas approprié pour les applications en temps réel dur, il est possible d'utiliser Haskell pour des applications en temps réel souples dans certains cas. Je ne connais pas les recherches actuelles, mais je ne pense pas que ce soit un problème insurmontable. Je soupçonne que des systèmes comme Yampa ou des systèmes de génération de code comme Atom sont peut-être la meilleure approche pour résoudre ce problème.

  3. Une "fuite de temps" est un problème spécifique au FRP commutable. La fuite se produit lorsqu'un système est incapable de libérer d'anciens objets, car il peut en avoir besoin si un basculement se produit à un moment donné dans le futur. Outre une fuite de mémoire (qui peut être assez grave), une autre conséquence est que, lorsque le basculement se produit, le système doit faire une pause pendant que la chaîne des anciens objets est parcourue pour générer l'état actuel.

Les bibliothèques frp non commutables telles que Yampa et les anciennes versions de reactive-banana ne souffrent pas de pertes de temps. Les bibliothèques FRP commutables emploient généralement l'un des deux schémas suivants: soit elles ont une «monade de création» spéciale dans laquelle les valeurs FRP sont créées, soit elles utilisent un paramètre de type «vieillissement» pour limiter les contextes dans lesquels les commutations peuvent se produire. elerea (et éventuellement netwire?) utilisent le premier, tandis que les bananes réactives récentes et le pamplemousse utilisent le second.

Par "frp commutable", j'entends celui qui implémente la fonction de Conal switcher :: Behavior a -> Event (Behavior a) -> Behavior a , ou une sémantique identique. Cela signifie que la forme du réseau peut changer de manière dynamique lors de son exécution.

Cela ne contredit pas vraiment la déclaration de @ ertes sur les interfaces monadiques: il s'avère que fournir une Monadinstance pour unEvent rend possible les fuites de temps, et avec l'une ou l'autre des approches ci-dessus, il n'est plus possible de définir les instances Monad équivalentes.

Enfin, bien qu'il reste encore beaucoup de travail à faire avec FRP, je pense que certaines des plates-formes les plus récentes (reactive-banana, elerea, netwire) sont suffisamment stables et matures pour que vous puissiez créer un code fiable à partir d'elles. Mais vous devrez peut-être passer beaucoup de temps à apprendre les tenants et les aboutissants afin de comprendre comment obtenir de bonnes performances.


2
Concernant les bibliothèques à base de flèches (Yampa, netwire), elles sont également commutables. La raison en est que les flèches ont un vieillissement intégré, vous ne pouvez pas vous en débarrasser. (Étant des transformateurs de flux, les flèches sont indépendantes de l'heure de début de leur flux d'entrée.)
Heinrich Apfelmus

3
N'oubliez pas l' ennemi de la banane réactive : le sodium .
Dan Burton

1
@HeinrichApfelmus: c'est un point intéressant. Je ne pense généralement pas que les bibliothèques basées sur des flèches soient commutables de la même manière que elerea / pamplemousse / current-reactive-banana. Je pense que leur changement est beaucoup plus proche de ce qui était requis dans les versions précédentes de reactive-banana. C'est juste un sentiment instinctif, je n'y ai pas suffisamment réfléchi pour même décrire ce que je veux dire.
John L

2
@DanBurton merci, j'essayais sans succès de me souvenir de ce nom. Je suis d'accord que le sodium devrait être considéré comme une bibliothèque de FRP moderne, bien qu'il ne soit pas aussi populaire que réactif-banana.
John L

Bien que la discussion en cours soit un peu difficile à suivre, elle semble indiquer qu'un système soft-realtime est en effet possible, à condition que le temps du GC puisse d'une manière ou d'une autre être limité. En tout cas merci pour votre excellente réponse.
mnish

20

Je vais énumérer quelques éléments dans l'espace Mono et .Net et un de l'espace Haskell que j'ai trouvé il n'y a pas si longtemps. Je vais commencer par Haskell.

Elm - lien

Sa description selon son site:

Elm vise à rendre le développement Web frontal plus agréable. Il introduit une nouvelle approche de la programmation GUI qui corrige les problèmes systémiques de HTML, CSS et JavaScript. Elm vous permet de travailler rapidement et facilement avec la mise en page visuelle, d'utiliser le canevas, de gérer les entrées utilisateur complexes et d'échapper à l'enfer des rappels.

Il a sa propre variante de FRP . En jouant avec ses exemples, il semble assez mature.

Extensions réactives - lien

Description de sa première page:

Reactive Extensions (Rx) est une bibliothèque pour la composition de programmes asynchrones et basés sur des événements à l'aide de séquences observables et d'opérateurs de requête de style LINQ. À l'aide de Rx, les développeurs représentent des flux de données asynchrones avec Observables, interrogent des flux de données asynchrones à l'aide d'opérateurs LINQ et paramétrent la concurrence dans les flux de données asynchrones à l'aide de Schedulers. En termes simples, Rx = Observables + LINQ + Schedulers.

Les extensions réactives proviennent de MSFT et implémentent de nombreux excellents opérateurs qui simplifient la gestion des événements. C'était open source il y a quelques jours à peine. Il est très mature et utilisé en production; à mon avis, cela aurait été une API plus agréable pour les API Windows 8 que celle fournie par la bibliothèque TPL; parce que les observables peuvent être à la fois chauds et froids et réessayés / fusionnés, etc., tandis que les tâches représentent toujours des calculs chauds ou effectués qui sont soit en cours d'exécution, défectueux ou terminés.

J'ai écrit du code côté serveur en utilisant Rx pour l'asynchronisme, mais je dois admettre qu'écrire fonctionnellement en C # peut être un peu ennuyeux. F # a quelques wrappers, mais il a été difficile de suivre le développement de l'API, car le groupe est relativement fermé et n'est pas promu par MSFT comme d'autres projets.

Son open sourcing est venu avec l'open sourcing de son compilateur IL-to-JS, donc il pourrait probablement bien fonctionner avec JavaScript ou Elm.

Vous pourriez probablement lier F # / C # / JS / Haskell très bien en utilisant un courtier de messages, comme RabbitMQ et SocksJS.

Boîte à outils Bling UI - lien

Description de sa première page:

Bling est une bibliothèque basée sur C # pour programmer facilement des images, des animations, des interactions et des visualisations sur WPF / .NET de Microsoft. Bling est orienté vers les technologues de conception, c'est-à-dire les concepteurs qui programment parfois, pour aider au prototypage rapide d'idées de conception d'interface utilisateur riches. Les étudiants, les artistes, les chercheurs et les amateurs trouveront également Bling utile comme outil pour exprimer rapidement des idées ou des visualisations. Les API et les constructions de Bling sont optimisées pour la programmation rapide du code à jeter par opposition à la programmation minutieuse du code de production.

Article LtU gratuit .

J'ai testé cela, mais je n'ai pas travaillé avec pour un projet client. Il a l'air génial, a une belle surcharge d'opérateur C # qui forme les liaisons entre les valeurs. Il utilise les propriétés de dépendance dans WPF / SL / (WinRT) comme sources d'événements. Ses animations 3D fonctionnent bien sur du matériel raisonnable. J'utiliserais ceci si je me retrouve sur un projet ayant besoin de visualisations; probablement en le portant sur Windows 8.

ReactiveUI - lien

Paul Betts, auparavant chez MSFT, maintenant chez Github, a écrit ce cadre. J'ai beaucoup travaillé avec et j'aime le modèle. Il est plus découplé que Blink (de par sa nature de l'utilisation de Rx et de ses abstractions) - ce qui facilite le test unitaire du code en l'utilisant. Le client github git pour Windows y est écrit.

commentaires

Le modèle réactif est suffisamment performant pour la plupart des applications exigeantes en performances. Si vous pensez au temps réel difficile, je parierais que la plupart des langages GC ont des problèmes. Rx, ReactiveUI créent une certaine quantité de petits objets qui doivent être GC, car c'est ainsi que les abonnements sont créés / supprimés et que les valeurs intermédiaires progressent dans la "monade" réactive des rappels. En général sur .Net, je préfère la programmation réactive à la programmation basée sur les tâches car les rappels sont statiques (connus au moment de la compilation, pas d'allocation) tandis que les tâches sont allouées dynamiquement (pas connu, tous les appels nécessitent une instance, des déchets créés) - et les lambdas se compilent en classes générées par le compilateur.

Évidemment, C # et F # sont strictement évalués, donc la fuite de temps n'est pas un problème ici. Idem pour JS. Cela peut cependant être un problème avec les observables rejouables ou mis en cache.


Merci pour la bonne réponse. Une des choses que j'ai aimé pour les implémentations Haskell FRP est qu'elles semblent me permettre de découpler proprement les calculs pour le contrôle u(t)et les simulations pour f(t). Est-ce le cas pour les implémentations F #?
mnish

Je suppose que vous pouvez dire que ces deux fonctions sont temporellement découplées, oui. Cependant, ils ne sont probablement pas découplés logiquement. ;)
Henrik

Autant que je sache, les extensions réactives et les autres packages plus perfectionnés axés sur l'interface utilisateur (et tout ce qui se trouve en dehors de Haskell, en fait) n'utilisent que la sémanique événementielle - c'est-à-dire qu'ils ont une notion d'événements que vous pouvez activer, mais pas une notion de signaux temporels continus qui peuvent interagir équationnellement. Pour construire guis c'est très bien, je pense. Cependant, pour la construction de simulations et de modèles, cela peut être malheureux.
sclv

Souhaitez-vous impliquer que toutes les implémentations de bibliothèques de programmation réactive fonctionnelle doivent modéliser le temps de manière continue plutôt que discrète? J'ai trouvé un article intitulé «Process Algebra with Timing: Real Time and Discrete Time» - est-ce un bon point de départ pour comprendre de quoi vous parlez?
Henrik

Je ne dis pas que tous doivent - certains le font, d'autres non. Mais ceux qui le font sont plus adaptés à certaines tâches, et ceux qui ne le sont pas davantage pour d'autres ...
sclv
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.