Selon Pippenger [1996] Lorsque l'on compare un système Lisp purement fonctionnel (et doté d'une sémantique d'évaluation stricte, et non paresseuse) à un système capable de modifier les données, un algorithme écrit pour le Lisp impur qui s'exécute en O( n ) peut être traduit en un algorithme dans le Lisp pur qui s'exécute en O( n journal n ) temps (sur la base des travaux de Ben-Amram et Galil [1992] sur la simulation de la mémoire à accès aléatoire en utilisant uniquement des pointeurs). Pippenger établit également qu'il existe des algorithmes pour lesquels c'est le mieux que l'on puisse faire ; il existe des problèmes qui sont O( n ) dans le système impur qui sont Ω( n journal n ) dans le système pur.
Il y a quelques mises en garde à faire au sujet de ce document. La plus importante est qu'il ne traite pas des langages fonctionnels paresseux, tels que Haskell. Bird, Jones et De Moor [1997]. démontrent que le problème construit par Pippenger peut être résolu dans un langage fonctionnel paresseux en O( n ), mais ils n'établissent pas (et pour autant que je sache, personne ne l'a fait) si un langage fonctionnel paresseux peut ou non résoudre tous les problèmes dans le même temps d'exécution asymptotique qu'un langage avec mutation.
Le problème construit par Pippenger requiert Ω( n journal n ) est spécifiquement construit pour atteindre ce résultat, et n'est pas nécessairement représentatif des problèmes pratiques du monde réel. Il y a quelques restrictions sur le problème qui sont un peu inattendues, mais nécessaires pour que la preuve fonctionne ; en particulier, le problème exige que les résultats soient calculés en ligne, sans pouvoir accéder à l'entrée future, et que l'entrée consiste en une séquence d'atomes d'un ensemble non limité d'atomes possibles, plutôt qu'un ensemble de taille fixe. De plus, l'article n'établit des résultats (borne inférieure) que pour un algorithme impur de temps d'exécution linéaire ; pour les problèmes qui nécessitent un temps d'exécution plus long, il est possible que le temps supplémentaire de O(log n ) observé dans le problème linéaire peut être "absorbé" dans le processus des opérations supplémentaires nécessaires aux algorithmes ayant des temps d'exécution plus importants. Ces clarifications et questions ouvertes sont explorées brièvement par Ben-Amram [1996] .
En pratique, de nombreux algorithmes peuvent être implémentés dans un langage purement fonctionnel avec la même efficacité que dans un langage avec des structures de données mutables. Pour une bonne référence sur les techniques à utiliser pour implémenter efficacement des structures de données purement fonctionnelles, voir Chris Okasaki, "Purely Functional Data Structures" [Okasaki 1998]. (qui est une version étendue de sa thèse [Okasaki 1996] ).
Tous ceux qui ont besoin de mettre en œuvre des algorithmes sur des structures de données purement fonctionnelles devraient lire Okasaki. Vous pouvez toujours obtenir au pire un résultat O(log n ) par opération en simulant une mémoire mutable avec un arbre binaire équilibré, mais dans de nombreux cas, vous pouvez faire beaucoup mieux que cela, et Okasaki décrit de nombreuses techniques utiles, des techniques amorties aux techniques en temps réel qui effectuent le travail amorti de manière incrémentielle. Les structures de données purement fonctionnelles peuvent être un peu difficiles à utiliser et à analyser, mais elles offrent de nombreux avantages, comme la transparence référentielle, qui sont utiles pour l'optimisation des compilateurs, le calcul parallèle et distribué et la mise en œuvre de fonctionnalités telles que le versioning, l'undo et le rollback.
Notez également que tout ceci ne traite que des temps d'exécution asymptotiques. De nombreuses techniques d'implémentation de structures de données purement fonctionnelles entraînent un certain ralentissement en facteur constant, dû à la comptabilité supplémentaire nécessaire à leur fonctionnement et aux détails d'implémentation du langage en question. Les avantages des structures de données purement fonctionnelles peuvent l'emporter sur ces ralentissements à facteur constant. Vous devrez donc généralement faire des compromis en fonction du problème en question.
Références
- Ben-Amram, Amir et Galil, Zvi 1992. "Sur les pointeurs et les adresses" Journal of the ACM, 39(3), pp. 617-648, juillet 1992
- Ben-Amram, Amir 1996. "Notes sur la comparaison entre Lisp pur et Lisp impur de Pippenger" Manuscrit non publié, DIKU, Université de Copenhague, Danemark.
- Bird, Richard, Jones, Geraint, et De Moor, Oege 1997. "Plus de hâte, moins de rapidité : évaluation paresseuse contre évaluation empressée" Journal of Functional Programming 7, 5 pp. 541-547, septembre 1997
- Okasaki, Chris 1996. "Structures de données purement fonctionnelles" Thèse de doctorat, Université Carnegie Mellon
- Okasaki, Chris 1998. "Structures de données purement fonctionnelles" Cambridge University Press, Cambridge, Royaume-Uni
- Pippenger, Nicholas 1996. "Pure Versus Impure Lisp" Symposium de l'ACM sur les principes des langages de programmation, pages 104-109, janvier 1996.
6 votes
De même que pour la programmation impérative, quelle qu'elle soit.
3 votes
@jldupont : Pour retourner le résultat d'un calcul bien sûr. Il existe de nombreux programmes sans effet secondaire. Ils ne peuvent simplement pas faire grand chose d'autre que de calculer sur leur entrée. Mais c'est toujours utile.
25 votes
Je peux le rendre aussi mauvais que vous le souhaitez, en écrivant mal mon code fonctionnel ! *grin* Je pense que votre question est "existe-t-il un problème pour lequel l'algorithme non destructif le plus connu est asymptotiquement pire que l'algorithme destructif le plus connu, et si oui, de combien ?"... est-ce exact ?
3 votes
Pourriez-vous donner un exemple du type de ralentissement qui vous intéresse ? Votre question est un peu vague.
0 votes
@itowlson - oui, c'est ce que je voulais dire. Je reconnais que c'était mal formulé.
6 votes
Un utilisateur a supprimé sa réponse, mais il a affirmé que la version fonctionnelle du problème des 8 reines s'exécutait en plus d'une minute pour n = 13. Il a admis qu'elle n'était pas "très bien écrite", alors j'ai décidé d'écrire ma propre version du problème des 8 reines en F# : pastebin.com/ffa8d4c4 . Inutile de préciser que mon programme purement fonctionnel calcule n = 20 en un peu plus d'une seconde.
0 votes
Quelques bons commentaires sur reddit : reddit.com/r/programming/comments/c76b8/