2011-07-06 3 views

Répondre

4

Comme couvre la question connexe, Practical use of curried functions?, il y a beaucoup de raisons pour lesquelles la valeur des personnes curryfication et utilisent, y compris:

  • améliorer la réutilisation du code - fonctions de cas particuliers sont simplement partiellement appliquées (et cari) fonctions génériques
  • améliorer la lisibilité du code - map (+2) est plus facile à lire que map (\x -> x + 2)
  • amélioration de la performance - curryfication peut rendre évidentes certaines spécialisations, et un bon compilateur génère la version spécialisée pour vous
  • amusant - code plus simple, plus beau code rend la vie plus agréable.
2

avantages réels que j'ai trouvé:

  • bugs en moins - Code de composition par la composition de la fonction tend à rendre le code plus correct que le flux de contrôle impératif. Par exemple, si vous utilisez « la carte » plutôt que « pour les boucles » vous éliminez le risque de nombreux « off par un » erreurs d'indexation

  • Mieux concurrency - et le code que vous créez avec des fonctions pures, sans effet secondaire est automatiquement thread safe. Ajoutez à cela des structures de données persistantes immuables et vous disposez d'une excellente recette pour écrire du code concurrent robuste. Clojure est particulièrement bon pour cela - voir http://www.infoq.com/presentations/Value-Identity-State-Rich-Hickey

  • code plus concis et facile à gérer - code fonctionnel semble dans mon analyse complètement non scientifique d'être considérablement plus court que le code impératif POO. Le bénéfice a tendance à être plus prononcé à mesure que les programmes prennent de l'ampleur. Je pense qu'il y a plusieurs raisons à cela:

    • La syntaxe des langages fonctionnels a tendance à être plutôt concise. Haskell et les différents Lisps par exemple ont tous les deux des syntaxes très simples et élégantes
    • Les langages fonctionnels tendent à encourager la composition (des fonctions d'ordre supérieur) plutôt que le "collage" de parties de programmes ensemble. Par conséquent, vous évitez une grande partie de la routine qui est inhérente à de nombreux autres paradigmes.
    • En ce qui concerne le point de composition, je trouve qu'il est plus facile d'appliquer le principe DRY dans les langages fonctionnels. Si vous voyez un pattern commun, il est presque toujours possible de l'extraire assez facilement dans une fonction d'ordre supérieur (ou une macro si vous êtes un Lisper) afin de pouvoir l'utiliser ailleurs.
  • testabilité - lorsque vous écrivez du code principalement avec des fonctions pures, il est très facile d'écrire des tests robustes.

Il y a quelques inconvénients à Ofset cela bien sûr:

  • Il est plus difficile d'écrire - vous avez besoin d'agilité mentale plus parce que vous avez besoin de tenir des concepts abstraits assez complexes dans votre tête. Cela aide si vous êtes un mathématicien entraîné (je suis) mais je trouve toujours écrire le code fonctionnel plus dur que la POO.
  • Il y a un surcoût lié aux performances - les langages fonctionnels utilisent divers processus qui impliquent nécessairement un certain niveau de surcharge. Bien que cela puisse être rendu très petit avec de bons compilateurs, il ne peut jamais être complètement éliminé.
  • Bibliothèque/outil suport - ceci est presque entièrement dû à la plus grande maturité des plates-formes et outils OOP, mais cela reste néanmoins un problème. À long terme, ce ne sera pas un problème, mais la meilleure solution que j'ai trouvée est d'utiliser Clojure qui peut bénéficier de la plupart des bibliothèques et des outils de la plate-forme Java.
+1

ah j'ai mal lu la question et répondu plus comme "quelle est la valeur de la programmation fonctionnelle". Oups! – mikera

1

Je dirais que c'est un peu comme Once and Only Once

en C/C++ je me écrire du code tel que

configure_grid (grid, first_column, last_column, action) { 
    for (i = first_column; i <= last_column; ++i) 
     // ... 
} 

configure_grids (action) { 
    congifure_grid (alpha, first_alpha, last_alpha, action); 
    congifure_grid (beta, first_beta, last_beta, action); 
} 

Au lieu d'écrire la boucle for une fois pour chacun des alpha et bêta . Ceci est analogue à l'exécution en code procédural. L'avantage ici est clair.

Curriculum est un concept théorique important, mais en termes pratiques, c'est l'avantage.

En fait, je me souviens avoir écrit une suite de test en C une fois, il était un peu comme ceci:

typedef bool (*predicate) (const type *); 

const char * argument; 

bool do_foo (const type * t) { 
    return bar (t, argument); 
} 

bool do_baz (const type * t) { 
    return bap (t, argument); 
} 

predicate foo (const char * arg) { 
    argument = arg; 
    return do_foo; 
} 

predicate baz (const char * arg) { 
    argument = arg; 
    return do_baz; 
} 

assert (for_all (data_set("alpha"), foo ("abc"))); 
assert (for_all (data_set("beta"), baz ("def"))); 

Ce fut en C pur, pas de tricherie macro etc. style fonctionnel et un peu comme currying. Ici, l'avantage est que vous pouvez voir en un coup d'œil exactement quels sont les cas de test. data_set est similaire - il lie son argument à une autre fonction qui récupère les données: for_all exécute le thunk, vérifie le prédicat et nettoie. Rangé.

Questions connexes