FP pour simulation et modélisation

12

Je suis sur le point de démarrer un projet de simulation / modélisation. Je sais déjà que la POO est utilisée pour ce genre de projets. Cependant, l'étude de Haskell m'a fait envisager d'utiliser le paradigme FP pour modéliser un système de composants. Permettez-moi d'expliquer:

Disons que j'ai un composant de type A, caractérisé par un ensemble de données (un paramètre comme la température ou la pression, une PDE et certaines conditions aux limites, etc.) et un composant de type B, caractérisé par un ensemble de données différent (différent ou même paramètre, PDE et conditions aux limites différentes). Supposons également que les fonctions / méthodes qui vont être appliquées sur chaque composant soient les mêmes (une méthode Galerkin par exemple). L'état mutable de l'objet serait utilisé pour les paramètres non constants.

Si je devais utiliser une approche POO, je créerais deux objets qui encapsuleraient les données de chaque type, les méthodes pour résoudre le PDE (l'héritage serait utilisé ici pour la réutilisation du code) et la solution au PDE.

D'un autre côté, si je devais utiliser une approche FP, chaque composant serait décomposé en parties de données et les fonctions qui agiraient sur les données afin d'obtenir la solution pour le PDE. Les paramètres non constants seraient passés en fonction d'autre chose (le temps par exemple) ou exprimés par une sorte de mutabilité (émulation de mutabilité, etc.). Cette approche me semble plus simple en supposant que les opérations linéaires sur les données seraient triviales.

Pour conclure, la mise en œuvre de l'approche FP serait-elle réellement plus simple et plus facile à gérer (ajouter un type de composant différent ou une nouvelle méthode pour résoudre le pde) par rapport à la POO?

Je viens d'un milieu C ++ / Fortran, et je ne suis pas un programmeur professionnel, alors corrigez-moi sur tout ce que je me trompe.

heaptobesquare
la source

Réponses:

7

Bonne question, j'ai réfléchi dans le même sens. Historiquement, le paradigme OO est né du besoin de simulation informatique - voir l'histoire de Simula - et malgré les premiers langages OO comme Smalltalk créés par des gens qui savaient ce qu'ils faisaient (par exemple Alan Kay), OO est maintenant sans doute surutilisé et apporte beaucoup trop de complexité accidentelle .

Généralement, les programmes de style FP seront plus courts, plus faciles à tester et plus faciles à modifier que les programmes OO. Comme Rob Harrop l'a dit dans son exposé, l'avenir est-il fonctionnel? , vous ne pouvez jamais obtenir plus simple que les fonctions et les données; les deux se composent à l'infini, pour construire toutes les abstractions nécessaires. Donc, une façon de répondre à votre question (ou suis-je simplement en train de la reformuler? :) est de demander, à quoi ressemblent les fonctions de plus haut niveau et les données d'entrée de plus haut niveau -> données de sortie? Ensuite, vous pouvez commencer à décomposer ces fonctions "alpha" et types de données dans la couche d'abstractions suivante, et répéter si nécessaire.

Une autre perspective (pas tout à fait des réponses) sur votre question est de regarder ce fil (avertissement, je l'ai commencé) sur StackOverflow, certaines des réponses sont très intéressantes: /programming/3431654/how-does- programmation-fonctionnelle-appliquer-aux-simulations

Ma propre opinion à ce stade est, à moins que vous ne modélisiez une situation où il y a vraiment des objets discrets qui n'interagissent que de manière définie (par exemple, un modèle de réseau informatique) - et qui correspondent donc directement aux capacités d'un message propre et propre - langage OO passant-paradigme - il est plus simple d'aller FP. Notez que même dans la communauté de programmation de jeux - où les simulations sont très répandues et les exigences de performances sont primordiales - les développeurs expérimentés s'éloignent du paradigme OO et / ou utilisent plus de FP, par exemple, voir cette discussion HN ou les commentaires de John Carmack sur FP

limist
la source
C'est bon de savoir que je ne suis pas le seul à douter de la POO en simulation et merci d'avoir répondu à ma question! J'avais lu les commentaires de John Carmack sur FP et j'ai pensé à implémenter certains aspects FP sur C ++ (copier les objets, ou rassembler l'entrée et la passer à une fonction) mais là encore je ne sais pas si je devrais commencer mon projet avec C ++ au lieu d'un langage FP, comme Haskell, car les aspects FP sont intégrés et vous n'exprimez la mutabilité que lorsque cela est nécessaire. Avez-vous continué à utiliser Clojure ou FP en général, étant donné que vous aviez un problème / question similaire?
heaptobesquare
@heaptobesquare - Oui, j'ai progressivement augmenté mon Clojure-fu dans le but d'y écrire des simulations. Rien n'est encore prêt à être montré, mais je ne vois aucun obstacle, et la conception de Clojure est magnifiquement pragmatique, par exemple, vous pouvez utiliser des transitoires / mutations si nécessaire, de plus ses agents sont bien adaptés aux aspects asynchrones. À un moment donné (pas de promesse quand) j'écrirai un article sur le sujet ...
limist
J'ai jeté un coup d'œil à Clojure mais je ne peux pas dire que j'aime les expressions S. Je sais que c'est pratique (le code Lisp est des données) mais est-il facile de s'y habituer?
heaptobesquare
@heaptobesquare - la syntaxe s-expressions / Lisp est en fait très facile à utiliser; choisissez d'abord un bon éditeur (Emacs ou vim, mon vote est pour Emacs, voir dev.clojure.org/display/doc/Getting+Started+with+Emacs ) qui a un mode pour Clojure, procurez-vous un bon livre (par exemple, Programmation Clojure ) et commencez à pirater. Au bout de quelques semaines tout au plus, la syntaxe disparaîtra en arrière-plan, comme il se doit - elle est si parfaitement cohérente que vous y penserez de manière exponentielle moins souvent, et libérerez les cycles mentaux pour des choses plus importantes. :)
limiste
Je vais certainement essayer alors. L'homoiconicité de Lisp est après tout intéressante.
heaptobesquare
2

À mon humble avis, pour presque toutes les tâches d'une complexité raisonnable, la question "est un style FP ou OOP est le meilleur choix" ne peut pas recevoir de réponse objective. En règle générale, dans une telle situation, la question n'est pas «soit FP ou OOP», mais comment combiner les meilleures parties des deux paradigmes pour résoudre votre problème.

Le problème que vous avez résolu ci-dessus semble être très mathématique, et je suppose que vous aurez besoin de quelques opérations matricielles. La POO est très bonne pour modéliser des types de données abstraits, et le calcul matriciel peut être facilement implémenté en tant qu '"objets matriciels" avec des opérations sur des matrices. L'implémentation d'une manière où toutes les opérations matricielles font partie d'une classe matricielle vous aide à garder les choses ensemble qui vont ensemble, afin de maintenir une bonne structure globale.

D'un autre côté, les PDE sont des équations sur les fonctions, et la solution peut être à nouveau fonctionnelle. Donc, utiliser une approche fonctionnelle pour ce type de "composants" peut sembler naturel ici. Ces fonctions peuvent avoir des paramètres matriciels, montrant un exemple de la façon de combiner OOP et FP. Un autre exemple serait une implémentation de classe matricielle, qui utilise des outils fonctionnels pour mapper une certaine opération à chaque élément de votre matrice. Donc, ici aussi, ce n'est pas "OOP versus FP" mais "OOP combiné avec FP" qui vous apporte les meilleurs résultats.

Doc Brown
la source
Merci pour votre réponse! Donc, si j'utilise C ++, j'encapsulerais uniquement les données (c'est-à-dire les paramètres, les conditions aux limites et le PDE sous forme matricielle) du composant dans un objet et définir les fonctions (même certaines d'ordre supérieur, dans le cas d'un paramètre est fonction de quelque chose d'autre), en dehors de la portée de l'objet, qui fonctionnerait sur les données de l'objet, serait-il efficace?
heaptobesquare
@heaptobesquare: honnêtement, je ne peux pas vous dire si ce sera efficace dans votre cas. Essayez, pensez grand, commencez petit. Commencez à programmer du "code traceur" ( artima.com/intv/tracer.html ) pour découvrir ce qui fonctionne le mieux et ce qui ne fonctionne pas. Et si vous arrivez à une situation où vous remarquez que quelque chose ne fonctionne pas correctement, refactorisez.
Doc Brown
Haskell a la bibliothèque Hmatrix, qui est des liaisons pour les bibliothèques BLAS / LAPACK, et une syntaxe très agréable pour cela, que je choisirais personnellement plutôt qu'une approche OOP.
paul
@paul: Merci, je vais certainement y jeter un œil! Les bibliothèques Haskell sont-elles généralement cohérentes et riches en contenu? Les wikis le disent mais est-ce un fait?
heaptobesquare
@heaptobesquare: La seule bibliothèque Haskell que j'ai utilisée dans une certaine mesure est Parsec (je l'ai utilisée pour écrire un assembleur), mais j'ai adoré l'utiliser. Je n'ai fait que l'exploration GHCI de Hmatrix et des liaisons Haskell OpenGL mais elles semblent assez sympas. Hmatrix semble être presque aussi concis que MATLAB (que j'ai utilisé un peu) - qui a été spécialement conçu pour ce genre de chose. D'après mon expérience limitée, les bibliothèques sont cohérentes - c'est parce que Haskell est construit sur un petit nombre de blocs de construction simples - et elles sont également riches parce que les Haskellers n'aiment pas faire des choses banales :)
paul