J'essaie de visualiser quelques systèmes physiques automatiques simples (comme des pendules, des 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)
où 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 saisi le livre "The Haskell School of Expression" de Paul Hudak, et j'ai découvert que le langage spécifique au domaine "FAL" (pour Functional Animation Language) qui y était présenté fonctionnait vraiment très bien pour mes systèmes de jouets simples (bien que certaines fonctions, notamment integrate
, semblait être un peu trop paresseux pour une utilisation efficace, mais facilement réparable).
Ma question est la suivante: quelle est l'alternative la plus mature, la plus à jour, la mieux entretenue et la plus adaptée aux performances pour des 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:
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 vicié. J'adore son code, mais peut-être devrais-je essayer d'autres alternatives plus à jour? Quelle est la principale différence entre eux, en termes de syntaxe/performances/stabilité d'exécution?
Pour citer un enquête en 2011, Section 6, " ... Les implémentations FRP ne sont toujours pas assez efficaces ou suffisamment prévisibles en termes de performances pour être utilisées efficacement dans des domaines qui exiger des garanties de latence ... ". Bien que l'enquête suggère quelques optimisations possibles intéressantes, étant donné que FRP existe depuis plus de 15 ans, j'ai l'impression que ce problème de performance pourrait être quelque chose très ou même intrinsèquement difficile à résoudre au moins en quelques années. Est-ce vrai?
Le même auteur de l'enquête parle de "fuites de temps" dans son blog . Le problème est-il unique à 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 basé sur FRP au fil du temps, si ce n'est pas assez performant?
S'agit-il toujours d'un projet de 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 un langage whaterver qui convient à 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!
À 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 met l'accent sur l'efficacité, la flexibilité et la prévisibilité. Il a son propre paradigme d'événement et peut être utilisé dans des domaines où le PRF traditionnel ne fonctionne pas, y compris les services réseau et les simulations complexes. Style: applicatif et/ou fléché. Auteur et mainteneur initial: Ertugrul Söylemez (c'est moi).
reactive-banana s'appuie sur le paradigme FRP traditionnel. 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 et mainteneur initial: Heinrich Apfelmus.
Vous devriez essayer les deux, mais en fonction de votre application, vous trouverez probablement l'un ou l'autre mieux adapté.
Pour les jeux, la mise en réseau, le contrôle de robots et les simulations, Netwire vous sera 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 du Control.Wire
module sur la page que j'ai liée.
Pour les interfaces utilisateur graphiques, votre meilleur choix est actuellement réactif-banane. Il a déjà une interface wx (en tant que bibliothèque séparée reactive-banana-wx) et Heinrich blogue beaucoup sur 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 de prévisibilité en temps réel. Cela 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 FRP pratiques n'offrent tout simplement pas d'interface monadique. Yampa a commencé cela et Netwire et réactive-banana s'appuient tous les deux sur cela.
Je ne connais aucun projet commercial ou autrement à grande échelle utilisant FRP en ce moment. Les bibliothèques sont prêtes, mais je pense que les gens ne le sont pas encore.
Bien qu'il existe déjà de bonnes réponses, je vais essayer de répondre à vos questions spécifiques.
réactif n'est pas utilisable pour les 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 réactive-banana, qui a été développée avec réactif comme inspiration, et en discussion avec Conal Elliott.
Bien que Haskell lui-même ne soit pas approprié pour les applications en temps réel difficiles, il est possible d'utiliser Haskell pour les applications en temps réel logicielles dans certains cas. Je ne connais pas la recherche actuelle, 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 probablement la meilleure approche pour résoudre ce problème.
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 commutateur devait se produire à un moment donné dans le futur. En plus d'une fuite de mémoire (qui peut être assez grave), une autre conséquence est que, lorsque le commutateur se produit, le système doit s'arrêter pendant que la chaîne d'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 fuites de temps. Les bibliothèques frp commutables emploient généralement l'un des deux schémas: 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 "vieillissant" pour limiter les contextes dans lesquels les commutations peuvent se produire. elerea (et éventuellement netwire?) utilisent le premier, alors que les bananes réactives récentes et le pamplemousse utilisent le second.
Par "frp commutable", je veux dire 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 dynamiquement pendant son fonctionnement.
Cela ne contredit pas vraiment la déclaration de @ ertes sur les interfaces monadiques: il s'avère que fournir une instance de Monad
pour un Event
rend les fuites de temps possibles, et avec l'une ou l'autre des approches ci-dessus, ce n'est plus possible pour 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 en construire du code fiable. Mais vous devrez peut-être passer beaucoup de temps à apprendre les tenants et aboutissants afin de comprendre comment obtenir de bonnes performances.
Je vais énumérer quelques éléments dans l'espace Mono et .Net et un dans l'espace Haskell que j'ai trouvé il n'y a pas si longtemps. Je vais commencer par Haskell.
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 disposition 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 . De jouer avec ses exemples, il semble assez mature.
Description de sa première page:
Reactive Extensions (Rx) est une bibliothèque pour composer des 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. Autrement dit, 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 seulement quelques jours. Il est très mature et utilisé en production; à mon avis, cela aurait été une meilleure API pour les API Windows 8 que la bibliothèque TPL fournit; 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 en cours d'exécution, en panne ou terminés.
J'ai écrit du code côté serveur en utilisant Rx pour asynchronocity, mais je dois admettre que l'écriture fonctionnelle en C # peut être un peu ennuyeuse. 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 source est venu avec l'open source de son compilateur IL-to-JS, donc il pourrait probablement bien fonctionner avec JavaScript ou Elm.
Vous pourriez probablement lier très bien F #/C #/JS/Haskell à l'aide d'un courtier de messages, comme RabbitMQ et SocksJS.
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 en 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 le 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.
Gratuit article Lt .
J'ai testé cela, mais je n'ai pas travaillé avec pour un projet client. Il a l'air génial, a une surcharge d'opérateur Nice C # qui forme les liaisons entre les valeurs. Il utilise des propriétés de dépendance dans WPF/SL/(WinRT) comme sources d'événements. Ses animations 3D fonctionnent bien sur un matériel raisonnable. Je l'utiliserais si je me retrouve sur un projet ayant besoin de visualisations; probablement le porter sur Windows 8.
Paul Betts, précédemment chez MSFT, maintenant chez Github, a écrit ce framework. J'ai beaucoup travaillé avec elle et j'aime le modèle. Il est plus découplé que Blink (par sa nature en utilisant Rx et ses abstractions) - ce qui facilite le test unitaire du code en l'utilisant. Le client github git pour Windows est écrit ici.
Le modèle réactif est suffisamment performant pour la plupart des applications exigeantes en performances. Si vous pensez en 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 GCed, 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 parce que les rappels sont statiques (connus au moment de la compilation, pas d'allocation) tandis que les tâches sont allouées dynamiquement (inconnu, tous les appels ont besoin d'une instance, des ordures sont créées) - 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 être un problème avec les observables rejouables ou mis en cache.