Autant je suis d'accord que les langages fonctionnels sont souvent très pratiques pour manipuler des structures de données non mutables (comme les arbres), autant je trouve que le résumé sur le « style impératif » est un peu simpliste : sur beaucoup d'algorithmes, boucle while avec variables locales ou récursivité terminale, c'est à peu près équivalent pour relecture et maintenance (de ce point de vue, la récursivité terminale, c'est juste une espèce de boucle while avec potentiellement des returns prématurés).
Et la partie sur les performances, le « efficacité d'exécution comparable, … voire un peu supérieure », est un peu simpliste aussi : sur certains algorithmes, la possibilité de les faire en place et en évitant des allocations mémoire inutiles (donc en utilisant la partie impérative du langage), change beaucoup les performances, rester dans le fonctionnel pur ça coûte cher. Le pdf d'état des lieux dit que « L'usage de traits impératifs peut se justifier dans certains cas », mais ils donnent comme exemple le fait d'éviter de passer un argument en paramètre à toutes les fonctions, qui me semble pour le coup évitable (rien n'empêche d'utiliser un record pour ne pas avoir une prolifération du nombre d'arguments).
Pour avoir codé en ocaml avec des map() et des fold_left(), j'ai vraiment du mal à réécrire des boucles, c'est beaucoup trop facile d'écrire de la merde (boucle infinie, offbyone, etc…). C'est vraiment ce qui me manque le plus en Go (golang) avec les types sommes.
S'il s'agissait de C j'aurais tendance à penser pareil, mais les map ou fold sur des listes deviennent des itérations avec range sur un tableau en Go, donc ça évite les soucis typiques des boucles, ça demande juste d'introduire explicitement la variable ou le tableau où on construit un nouveau résultat, donc c'est juste plus verbeux, avec l'avantage que la même construction sert à faire map et fold, et qu'il n'y a pas à se souvenir que c'est fold_left qu'il faut faire et pas fold_right, ni se rappeler (ou demander à merlin) l'ordre des arguments pas forcément intuitif (l'inverse entre OCaml et Coq, par exemple). Pour les types somme, je suis assez d'accord, mais c'est pas intrinsèquement fonctionnel comme truc, je dirais.
La seule construction que je ne vois pas comment réaliser à la fois efficacement et de façon commode dans un langage impératif un peu haut-niveau, c'est la récursivité terminale entre fonctions mutuellement récursives (comme truc approchant, je vois que le retour de pointeur vers une fonction, qui a le défaut de faire des sauts calculés non prévisibles).
Plus compact, je veux bien — et encore, pas tant que ça dès que la fonction anonyme à appliquer n'est pas triviale et ne tient pas sur une ligne.
Plus lisible, honnêtement, je suis mitigé là-dessus. D'un point de vue scientifique, la lisibilité me semble être un sujet pas évident : il ne s'agit pas de compter le nombre de caractères ou de lignes, mais la vitesse avec laquelle on les comprend, qui dépend de beaucoup de facteurs, entre autres individuels. Comme cas extrême, les langages style APL comme J permettent d'écrire des fold et des map de façon plus concise que OCaml ou Haskell, et se vantent d'être plus lisibles et productifs avec suffisamment d'entraînement. Certains allergiques au scroll vont jusqu'à essayer d'APLiser du C et soutenir qu'il s'agit là d'un style avec une longue courbe d'apprentissage mais plus lisible et moins propice aux erreurs avec de l'entraînement (si, si, il y en a qui soutiennent ça).
Personnellement, je suis assez sceptique — j'ai pas d'avis tranché, car pas assez d'habitude avec ces langages extrêmement concis pour les fonctions d'ordre supérieur (et encore, j'ai passé quand même pas mal d'heure à m'amuser avec, car c'est sympa de pouvoir écrire des algos non triviaux interactivement en repl). En vrai, j'ai quand même l'impression que pour un logiciel « normal » (disons où tout ne s'emboîte pas à coup de fold/map et avec 90% de logique simple), c'est même pas significativement plus court. Donc on met tous quelque part la barre pour un optimum de densité du code pour une meilleure lisibilité, est-ce que ça penche plutôt vers le fold/map d'OCaml ou un range de Go, ou du code à la J, je pense que ça dépend des gens, mais sauf besoin spécifique, je parie que plus de monde pencherait pour un simple range à la Go (perso, je saurais pas trop dire).
Disons que si tu vois un map, cela fait un map. Si tu vois un "for… range", tu n'en sais rien, cela peut être un map, un fold, il faut analyser le code en dessous pour le savoir. Cela peut aussi avoir des effets de bord.
Posté par kantien .
Évalué à 2.
Dernière modification le 04 avril 2018 à 17:52.
S'il s'agissait de C j'aurais tendance à penser pareil, mais les map ou fold sur des listes deviennent des itérations avec range sur un tableau en Go […]
Ou alors, pour être plus générique sur la conception des itérateurs, utiliser des foncteurs applicatifs : The Essence of the Iterator Pattern.
Pour les types somme, je suis assez d'accord, mais c'est pas intrinsèquement fonctionnel comme truc, je dirais.
Effectivement, voir le chapitre 1 de ce cours de programmation avancée pour la comparaison entre Java et OCaml sur la manière de définir des types algébriques.
La seule construction que je ne vois pas comment réaliser à la fois efficacement et de façon commode dans un langage impératif un peu haut-niveau, c'est la récursivité terminale entre fonctions mutuellement récursives (comme truc approchant, je vois que le retour de pointeur vers une fonction, qui a le défaut de faire des sauts calculés non prévisibles).
Avec des goto ? :-P
Ok, ---> [] …
Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.
# Le premier fichier PDF est intéressant
Posté par Guillawme (site web personnel, Mastodon) . Évalué à 1.
https://www.ssi.gouv.fr/uploads/IMG/pdf/LaFoSec_-_Etat_des_lieux_des_langages_fonctionnels.pdf
# Fonctionnel vs Impératif
Posté par anaseto . Évalué à 4.
Autant je suis d'accord que les langages fonctionnels sont souvent très pratiques pour manipuler des structures de données non mutables (comme les arbres), autant je trouve que le résumé sur le « style impératif » est un peu simpliste : sur beaucoup d'algorithmes, boucle while avec variables locales ou récursivité terminale, c'est à peu près équivalent pour relecture et maintenance (de ce point de vue, la récursivité terminale, c'est juste une espèce de boucle while avec potentiellement des returns prématurés).
Et la partie sur les performances, le « efficacité d'exécution comparable, … voire un peu supérieure », est un peu simpliste aussi : sur certains algorithmes, la possibilité de les faire en place et en évitant des allocations mémoire inutiles (donc en utilisant la partie impérative du langage), change beaucoup les performances, rester dans le fonctionnel pur ça coûte cher. Le pdf d'état des lieux dit que « L'usage de traits impératifs peut se justifier dans certains cas », mais ils donnent comme exemple le fait d'éviter de passer un argument en paramètre à toutes les fonctions, qui me semble pour le coup évitable (rien n'empêche d'utiliser un record pour ne pas avoir une prolifération du nombre d'arguments).
[^] # Re: Fonctionnel vs Impératif
Posté par Nicolas Boulay (site web personnel) . Évalué à 3.
Pour avoir codé en ocaml avec des map() et des fold_left(), j'ai vraiment du mal à réécrire des boucles, c'est beaucoup trop facile d'écrire de la merde (boucle infinie, offbyone, etc…). C'est vraiment ce qui me manque le plus en Go (golang) avec les types sommes.
"La première sécurité est la liberté"
[^] # Re: Fonctionnel vs Impératif
Posté par anaseto . Évalué à 2.
S'il s'agissait de C j'aurais tendance à penser pareil, mais les map ou fold sur des listes deviennent des itérations avec
range
sur un tableau en Go, donc ça évite les soucis typiques des boucles, ça demande juste d'introduire explicitement la variable ou le tableau où on construit un nouveau résultat, donc c'est juste plus verbeux, avec l'avantage que la même construction sert à faire map et fold, et qu'il n'y a pas à se souvenir que c'estfold_left
qu'il faut faire et pasfold_right
, ni se rappeler (ou demander à merlin) l'ordre des arguments pas forcément intuitif (l'inverse entre OCaml et Coq, par exemple). Pour les types somme, je suis assez d'accord, mais c'est pas intrinsèquement fonctionnel comme truc, je dirais.La seule construction que je ne vois pas comment réaliser à la fois efficacement et de façon commode dans un langage impératif un peu haut-niveau, c'est la récursivité terminale entre fonctions mutuellement récursives (comme truc approchant, je vois que le retour de pointeur vers une fonction, qui a le défaut de faire des sauts calculés non prévisibles).
[^] # Re: Fonctionnel vs Impératif
Posté par Nicolas Boulay (site web personnel) . Évalué à 3.
Si tu empiles les map, ou les fold, c'est bien plus compact et lisible, sur une ligne que explosé sur 3 ranges et bloc de code.
"La première sécurité est la liberté"
[^] # Re: Fonctionnel vs Impératif
Posté par anaseto . Évalué à 2.
Plus compact, je veux bien — et encore, pas tant que ça dès que la fonction anonyme à appliquer n'est pas triviale et ne tient pas sur une ligne.
Plus lisible, honnêtement, je suis mitigé là-dessus. D'un point de vue scientifique, la lisibilité me semble être un sujet pas évident : il ne s'agit pas de compter le nombre de caractères ou de lignes, mais la vitesse avec laquelle on les comprend, qui dépend de beaucoup de facteurs, entre autres individuels. Comme cas extrême, les langages style APL comme J permettent d'écrire des fold et des map de façon plus concise que OCaml ou Haskell, et se vantent d'être plus lisibles et productifs avec suffisamment d'entraînement. Certains allergiques au scroll vont jusqu'à essayer d'APLiser du C et soutenir qu'il s'agit là d'un style avec une longue courbe d'apprentissage mais plus lisible et moins propice aux erreurs avec de l'entraînement (si, si, il y en a qui soutiennent ça).
Personnellement, je suis assez sceptique — j'ai pas d'avis tranché, car pas assez d'habitude avec ces langages extrêmement concis pour les fonctions d'ordre supérieur (et encore, j'ai passé quand même pas mal d'heure à m'amuser avec, car c'est sympa de pouvoir écrire des algos non triviaux interactivement en repl). En vrai, j'ai quand même l'impression que pour un logiciel « normal » (disons où tout ne s'emboîte pas à coup de fold/map et avec 90% de logique simple), c'est même pas significativement plus court. Donc on met tous quelque part la barre pour un optimum de densité du code pour une meilleure lisibilité, est-ce que ça penche plutôt vers le fold/map d'OCaml ou un range de Go, ou du code à la J, je pense que ça dépend des gens, mais sauf besoin spécifique, je parie que plus de monde pencherait pour un simple range à la Go (perso, je saurais pas trop dire).
[^] # Re: Fonctionnel vs Impératif
Posté par Nicolas Boulay (site web personnel) . Évalué à 5.
Disons que si tu vois un map, cela fait un map. Si tu vois un "for… range", tu n'en sais rien, cela peut être un map, un fold, il faut analyser le code en dessous pour le savoir. Cela peut aussi avoir des effets de bord.
"La première sécurité est la liberté"
[^] # Re: Fonctionnel vs Impératif
Posté par kantien . Évalué à 2. Dernière modification le 04 avril 2018 à 17:52.
Ou alors, pour être plus générique sur la conception des itérateurs, utiliser des foncteurs applicatifs : The Essence of the Iterator Pattern.
Effectivement, voir le chapitre 1 de ce cours de programmation avancée pour la comparaison entre Java et OCaml sur la manière de définir des types algébriques.
Avec des
goto
? :-POk,
---> []
…Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.
[^] # Re: Fonctionnel vs Impératif
Posté par anaseto . Évalué à 2.
C'est pour ça que j'avais écris « de façon commode » :)
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.