La plupart des autres réponses se sont concentrées sur le côté performance (parallélisme) de la programmation fonctionnelle, ce que je pense est très important. Cependant, vous avez spécifiquement posé des questions sur la productivité, comme dans, pouvez-vous programmer la même chose plus rapidement dans un paradigme fonctionnel que dans un paradigme impératif.
Je trouve en fait (par expérience personnelle) que la programmation en F # correspond mieux à ma façon de penser, et donc c'est plus facile. Je pense que c'est la plus grande différence. J'ai programmé à la fois en F # et C #, et il y a beaucoup moins de "combat contre le langage" en F #, ce que j'adore. Vous n'avez pas à penser aux détails en F #. Voici quelques exemples de ce que j'ai trouvé que j'apprécie vraiment.
Par exemple, même si F # est typé statiquement (tous les types sont résolus au moment de la compilation), l'inférence de type détermine quels types vous avez, vous n'avez donc pas à le dire. Et s'il ne peut pas le comprendre, il rend automatiquement votre fonction / classe / quel que soit le générique. Vous n'avez donc jamais à écrire de générique, tout est automatique. Je trouve que cela signifie que je passe plus de temps à réfléchir au problème et moins à le mettre en œuvre. En fait, chaque fois que je reviens à C #, je trouve que cette inférence de type me manque vraiment, vous ne réalisez jamais à quel point c'est distrayant tant que vous n'avez plus besoin de le faire.
Aussi en F #, au lieu d'écrire des boucles, vous appelez des fonctions. C'est un changement subtil, mais significatif, car vous n'avez plus à penser à la construction de la boucle. Par exemple, voici un morceau de code qui passerait et correspondrait à quelque chose (je ne me souviens pas de quoi, c'est d'un puzzle de projet Euler):
let matchingFactors =
factors
|> Seq.filter (fun x -> largestPalindrome % x = 0)
|> Seq.map (fun x -> (x, largestPalindrome / x))
Je me rends compte que faire un filtre puis une carte (c'est une conversion de chaque élément) en C # serait assez simple, mais il faut penser à un niveau inférieur. En particulier, vous devrez écrire la boucle elle-même et avoir votre propre instruction if explicite, et ce genre de choses. Depuis l'apprentissage de F #, je me suis rendu compte que je trouvais plus facile de coder de manière fonctionnelle, où si vous voulez filtrer, vous écrivez "filtre", et si vous voulez mapper, vous écrivez "carte", au lieu d'implémenter chacun des détails.
J'adore aussi l'opérateur |>, qui, je pense, sépare F # d'ocaml, et peut-être d'autres langages fonctionnels. C'est l'opérateur pipe, il vous permet de "canaliser" la sortie d'une expression dans l'entrée d'une autre expression. Cela fait que le code suit ce que je pense davantage. Comme dans l'extrait de code ci-dessus, c'est-à-dire "prenez la séquence de facteurs, filtrez-la, puis mappez-la". C'est un niveau de réflexion très élevé, que vous n'obtenez pas dans un langage de programmation impératif parce que vous êtes tellement occupé à écrire la boucle et les instructions if. C'est la chose qui me manque le plus chaque fois que je vais dans une autre langue.
Donc, en général, même si je peux programmer à la fois en C # et en F #, je trouve qu'il est plus facile d'utiliser F # parce que vous pouvez penser à un niveau supérieur. Je dirais que parce que les plus petits détails sont supprimés de la programmation fonctionnelle (au moins en F #), je suis plus productif.
Edit : J'ai vu dans l'un des commentaires que vous avez demandé un exemple d '"état" dans un langage de programmation fonctionnel. F # peut être écrit impérativement, voici donc un exemple direct de la façon dont vous pouvez avoir un état mutable en F #:
let mutable x = 5
for i in 1..10 do
x <- x + i