Programmation fonctionnelle en Swift et autres langages
maito
Membre
Bon merci à tous et je vois que vous utilisez beaucoup la programmation fonctionnelle! Auriez-vous de bonnes ressources pour s'y mettre?
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Il y a ce livre que je n'ai pas lu:
https://www.objc.io/books/functional-swift/
Mais personnellement, je m'intéresse plutôt aux langages fonctionnels comme Haskell, Elm ou Clojure.
On ne peut pas consideÌrer Swift comme un langage fonctionnel ?
On reste quand même assez éloigné d'un langage fonctionnel pur, comme Haskell qui n'a pas de variables, pas d'état (donc pas de classes), qui est vraiment optimisé pour itérer, et travaille toujours en évaluation paresseuse.
D'un côté, tu as une approche pragmatique: apporter les éléments de la programmation fonctionnelle les plus utiles. De l'autre, une absence de compromis. Personnellement, j'aime bien les deux approches, même si je vois mal comment les concilier.
Peut-on créer des applications classiques avec Haskell (interactions diverses avec l'utilisateur, graphismes, sauvegarde de données, etc..) ou c'est limité à gérer des problèmes plus ou moins matheux ?
Je pense que ceci s'explique par deux facteurs. Le premier est que la documentation est justement orientée vers cet apprentissage très scolaire. Par exemple, les bouquins vont te faire 3 chapitres sur les monades avant de te dire comment lire ou écrire dans un fichier. Alors que quand on débute avec la langage, on se moque des concepts mathématiques sous-jacents.
Le deuxième facteur est qu'en Haskell, on va essayer de bannir tous les états, ou du moins isoler au maximum le code qui y fait appel. Or, dans la vraie vie, les états sont omni-présents: une touche est appuyée ou non, un pixel a une certaine couleur. Il n'y a pas eu assez de réflexion quant à la manière d'intégrer la gestion des événements dans Haskell.
C'est pour cela que je trouve Elm (http://elm-lang.org) très intéressant: sa syntaxe et ses concepts sont empruntés à Haskell, mais il propose une solution à la gestion des événements: la programmation réactive. Et ça marche!
Nous arrivons à une époque charnière: la programmation objet s'avère trop compliquée et nous exploitons mal la concurrence des traitements. Les langages classiques ne sont pas adaptés. C'est pour cela que ça bouillonne autour de la programmation fonctionnelle: marre des états! Utilisons des structures immutables (merci Clojure), générons des signaux (merci Redux), et reconstruisons rapidement l'affichage.
Pas étonnant qu'on voie apparaitre du Reactive Cocoa, du React, et RxSwift.
Je me suis posé la question, parce que la fiche Wiki d'Haskell ne contient que des exemples "matheux". Cela m'a rappelé ma très vague approche de l'APL il y a fort longtemps : des résolutions de problèmes mathématiques et rien d'autre.
J'ai un peu du mal à comprendre cette programmation reactive (enfin surtout du mal à trouver du temps pour m'y intéresser). C'est quoi et ça apporte quoi ?
Et pour la prog object j'ai toujours trouveÌ ça super naturel justement.
Si on peut faire de la programmation fonctionnelle avec swift pourquoi ne pas rester avec swift ?
J'ai fait un peu de XSLT, c'était horrible.
Ca ne ressemble pas à la vie. Il n' y a pas de déroulement, pas de causes, ni d'effets, pas d'états.
C'est "naturel" parce que tu baignes dedans.
La POO a été inventée pour les interfaces graphiques. Aussi, elle se prête particulièrement bien pour décrire des éléments concrets. Par exemple, un bouton: il s'inscrit dans un rectangle, il s'affiche, son aspect change quand on l'appuie, et quand il est déclenché, il envoie un message à sa cible.
Considère déjà la classe abstraite UIControl dont hérite UIButton. C'est déjà plus difficile de dire quel est son rôle, non ?
L'un des problèmes majeurs de la POO est qu'il est difficile de définir les classes. Le cahier des charges dit: "si l'acheteur a moins de 20 ans, réduire le tarif de 15%". Nous avons le Quoi, mais comment passer au Comment ? Quels objets définir ? Comment communiquent-ils ?
L'autre problème est que comme les données sont encapsulées dans les objets, comment les injecter dedans ? Pour un bouton, c'est déjà complexe, alors pour représenter une base de données...
Je ne dis pas que c'était mieux sans la POO. Je dis qu'il faut être conscient de ses limites, et en même temps revenir à l'essence de la POO: pas un simple moyen de grouper traitements et données. Dans l'esprit de SmallTalk, les objets sont les plus simples possibles, et le comportement émerge de la manière dont ils sont interconnectés.
Un objet client avec ses propriétés dont la date de naissance.
Un objet produit.
Un objet réduction avec une méthode canApplyToCustomer(Customer customer, Product product).
Après on peut raffiner avec des protocoles pour limiter l'effet spaghetti inhérent à la programmation objet.
La POO est naturelle car tu peux créer une classe par objet réel que tu manipules et tu as peu de chances de te tromper.
L'intelligence humaine isole des objets, les classe en catégories. Elle identifie des causes, des effets et des intentions dans tous les phénomènes même quand il n'y a que du hasard.
La POO avec un déroulement séquentielle colle bien à ce fonctionnement.
La POO n'est pas parfaite non plus et c'est bien de faire des recherches dans d'autres modes de programmation.
Cela permet de l'enrichir avec des nouvelles possibilités (map, reduce, les functors, plus d'immutabilité, etc).
D'autre part, à froid sans consulter Wikipedia, je ne crois pas que la POO a été inventée pour l'interface graphique mais plutôt pour entériner une manière de programmer en C, des bonnes pratiques, qui consistaient à encapsuler les données et à concevoir des structures comme des poupées russes.
Pour revenir à XLST qui a une approche fonctionnelle, c'est un langage très pratique pour certaines transformations XML, mais il faut à mon avis le mettre en place à partir d'une structure POO plus classique pour ne transformer que des parties de XML.
De même, selon moi, la fonction map ne doit être utilisée que pour effectuer des transformations mais pas pour planquer des algorithmes qui seraient plus compréhensibles avec une boucle classique.
Donc des conceptions fonctionnelles, mais une approche pure pour se la péter avec des one-liners que seul les doctorants en math peuvent comprendre, je ne vois pas l'intérêt:
Je ne connais pas suffisamment l'histoire de l'informatique pour savoir comment les langages objets ont étés inventés. Mais il me semble qu'ils répondent à un besoin naturel : donner des ordres à des outils "domestiques", sans avoir besoin d'expliquer comment faire. Et construire des programmes à partir de composants standards réutilisables, sans avoir à tout refaire/tester/valider. Cela se rapproche des concepts de l'industrie, qui consiste essentiellement à assembler des objets à partir de pièces détachées.
"Alfred, ouvrez la porte"
"Alfred, apportez-moi du thé"
"Alfred, quel jour sommes-nous ?"
"Picasso, dessine-moi un mouton"
L'objet Alfred a besoin d'un objet Cuisine pour préparer le thé. C'est tellement plus rapide d'utiliser un outil/cuisine standard que d'en créer/valider une nouvelle.
Bref, j'ai tendance à penser que les langages objets ont été conçus pour permettre l'industrialisation et la réutilisation du code, dans tous les domaines, pas spécifiquement les interfaces graphiques.
Le fait de grouper données et traitements est issu de Simula 2.
Mais le premier vrai langage objet comme nous connaissons est SmallTalk, qui a été inventé au PARC de Xerox, en même temps que l'interface graphique moderne. Alan Kay a toujours regretté d'avoir appelé ça la programmation orientée objet. Il aurait préféré "orientée messages".
Quels outils te permettent d'arriver à cette architecture ?
C'est là que je veux en venir. Je ne dis pas qu'on ne peut pas y arriver avec de l'expérience, mais que ça n'a rien de naturel.
Historiquement, on a commencé par les interfaces graphiques, puis on s'est dit que ses qualités pourraient s'étendre à d'autres domaines.
La réutilisation du code existait déjà ! Un algorithme est réutilisable, même s'il impose que les données soient organisées d'un certaine manière. Ce qu'apporte la POO, c'est plutôt l'abstraction.
Et puis entre nous, quel pourcentage de ton code est vraiment réutilisable tel quel dans un autre projet ?
La notion d'un objet client est intuitive. C'est la même chose qu'une fiche papier.
Idem pour un objet/fiche produit.
Un objet réduction .. euh ..
Je pense que ce n'est pas nécessaire d'opposer les deux et de choisir l'un ou l'autre pour ses besoins mais de les combiner comme le fait un peu Swift qui n'est pas résolument un langage fonctionnel.
Ce que je trouve intéressant dans la programmation fonctionnel ou du moins dans ses concepts c'est de ne pas se préoccuper des états et qu'au niveau lecture de code c'est plus simple puisque on applique pas le comment mais le quoi.
Déjà , partons du problème: nous avons de plus en plus de traitements asynchrones qui influent les uns sur les autres.
Je te donne un exemple:
- j'affiche une page, au début vide
- je lance donc une requête pour avoir ses données
- mais attends, pour accéder au données, l'utilisateur doit être connecté
- s'il n'est pas connecté, j'affiche la page de connexion
- si l'utilisateur entre un couple identifiant et mode de passe valide, on peut revenir à la page précédente et répondre à la requête
- sinon, on abandonne, etc...
Ceci est un exemple courant dans une application iOS. On voit tout de suite que la complexité augmente à chaque étape qui peut avoir plusieurs issues. En pratique, c'est difficile à gérer puisqu'il faut prévoir tous les cas. On constate qu'il y a aussi un mélange entre les requêtes réseau, le modèle et les vues. Qui va gérer ça? Le UIViewController, comme d'habitude, comme s'il n'était pas déjà assez gros et intestable.
En gros, l'idée de la programmation Réactive, c'est qu'il n'y a qu'un canal central de communication. On peut soit y envoyer des signaux, soit s'abonner pour être averti de l'apparition d'un signal. À la base, ça ressemble donc beaucoup au design pattern Observateur, implémenté chez nous sous la forme de NSNotificationCenter.
Où la programmation réactive va plus loin, c'est qu'on peut combiner les signaux ce qui permet de créer des règles complexes et attendre qu'un signal arrive pour le combiner, etc. C'est particulièrement intéressant parce que ça permet de déterminer le comportement de façon déclarative, plutôt que conditionnelle. C'est un gage de fiabilité et surtout de flexibilité.
- j'affiche une page, au début vide
- j'émets un signal pour lancer une requête, et je m'abonne pour recevoir la réponse
- un objet Modèle qui écoutait voit qu'on veut une requête
- mais attends, pour accéder au données, l'utilisateur doit être connecté: l'objet envoie un signal pour se connecter et combine le signal avec la condition d'une connexion réussie
- un contrôleur voit qu'un signal pour afficher la page de connexion
- s'il n'est pas connecté, j'affiche la page de connexion
- des signaux sont émis à chaque frappe dans les deux champs de texte. Ils sont combinés pour valider le bouton "Connecter" etc.
Je pense que tu vois où je veux en venir. Ce qui est bien, c'est que toute la logique est donnée de façon déclarative, et l'architecture est plus simple: pas besoin de délégation, blocs, KVO, notifications, etc.
Après, j'avoue ne pas avoir énormément d'expérience sur le sujet non plus!
Exactement. Les deux ont leur place, et aucun n'est une panacée. "No silver bullet".
Ok
Recoder un algorithme c'est introduire le risque d'une erreur humaine.
Tout ce qui se trouve dans les frameworks, ces gigantesques bibliothèques d'objets réutilisables et standardisés.
J'avais imaginé un système de ce genre il y a une quinzaine d'année, en pensant à la manière dont fonctionnaient les bateaux à l'époque de la marine à voile, par échange de signaux sonores entre plusieurs intervenants.
ça a l'air vraiment pas mal mais j'ai ça doit quand meme bouffer pas mal en ressources non ?
D'autant que le coÌ‚teÌ asynchrone doit pas trop aider quand on parle d'UI et autres. Mais je vais essayer de trouver du temps pour m'y intéresser un peu plus.
Merci pour la réponse détaillée en tout cas.
C'est la pastille rouge qu'on pose sur les étiquettes pendant les soldes. C'est la réduction. La rouge c'est 50 %, la pastille orange c'est 30%.
Mais je reconnais que la réduction en tant qu'objet c'est déjà moins naturel que le client ou le produit.
C'est moins naturel parce que ce n'est pas un objet physique, mais une opération mathématique. Notre cerveau de mammifère chasseur-cueilleur n'est pas fait pour manipuler intuitivement des objets mathématiques. Il faut un apprentissage pour ça, tandis qu'utiliser un outil physique est quasi-instinctif (comme une pierre ou un bâton).
Oui mais on a jamais dis que le paradigme OO devait forcement caractériser des choses tangibles.
ça me permet de rebondir sur ce que CeÌroce disait plus haut concernant NSControl. C'est une catégorie et ça ne pose pas de problème en tant qu'object de plus son caractère abstrait montre bien que c'est un concept et rien de concret.
Si on reprend les exemples multi-séculaire des bouquins qui sont censeÌs t'apprendre la POO tu te retrouvera toujours avec un truc du genre Chat et Chien qui dérivent de Mammifère qui derive lui même d'Animal.
Donc oui l'abstraction est une des composantes majeures et de fait très importantes du paradigme OO. Sinon sur le reste je suis assez d'accord avec CeÌroce.
Je vais essayer de creuser un peu plus dans le sens du Reactive Programming ça me parait aussi assez naturel. Quelqu'un a une bonne crémerie pour utiliser ça avec Swift ?
Commence peut-être par là :
https://medium.com/design-x-code/elmification-of-swift-af14b7f92b30#.7w4vpmy3g
D'un point de vue strictement pédagogique, RxSwift me parait la meilleure manière de s'y mettre, parce que c'est une implémentation relativement directe et simple.