29 votes

Existe-t-il des anti-modèles documentés pour la programmation fonctionnelle ?

Le mois prochain, je vais travailler sur un nouveau projet de R&D qui adoptera un langage de programmation fonctionnel (j'ai voté pour Haskell, mais pour l'instant F# a obtenu plus de consensus). J'ai déjà joué avec ces langages pendant un certain temps et développé quelques outils en ligne de commande avec eux, mais il s'agit d'un projet plus important et j'essaie d'améliorer mes connaissances et mes techniques de programmation fonctionnelle. J'ai également lu beaucoup sur le sujet, mais je ne trouve aucun livre ou ressource qui documente les anti-modèles dans le monde de la programmation fonctionnelle.

Maintenant, apprendre les anti-modèles signifie que apprendre à connaître les échecs d'autres personnes intelligentes Je suis assez expérimenté pour choisir judicieusement quand quelque chose qui est généralement un anti-modèle, répond parfaitement à mes besoins. Mais je peux choisir cela parce que je connais la leçon apprise par d'autres gars intelligents.

Ainsi, ma question est la suivante : existe-t-il des documenté anti-modèles en programmation fonctionnelle ? Jusqu'à présent, tous mes collègues m'ont dit qu'ils n'en connaissaient aucun, mais ils ne peuvent pas dire pourquoi.

  • Si oui, veuillez inclure un seul lien vers une source faisant autorité (un catalogue, un essai, un livre ou équivalent).
  • Si non, veuillez appuyer votre réponse en un théorème propre .

S'il vous plaît ne transformez pas cette question en liste : il s'agit d'une question booléenne qui nécessite simplement une preuve pour évaluer la réponse. Par exemple, si vous êtes Oleg Kiselyov, "Oui" est suffisant, puisque tout le monde pourra trouver votre essai sur le sujet. Soyez tout de même généreux.

Notez que je recherche des anti-modèles formels, et non de simples mauvaises habitudes ou mauvaises pratiques.

De la Lien vers l'article de wikipedia sur les anti-modèles. :

... au moins deux éléments clés doivent être présents pour distinguer formellement un véritable anti-modèle d'une simple mauvaise habitude, mauvaise pratique ou mauvaise idée :

  1. un schéma répété d'action, de processus ou de structure qui semble initialement bénéfique, mais qui produit finalement plus de mauvaises conséquences que de résultats bénéfiques, et
  2. il existe une solution alternative clairement documentée, éprouvée dans la pratique réelle et reproductible.

De plus, par "documenté", j'entends quelque chose de auteurs faisant autorité o sources connues .

Les langues auxquelles je suis habitué sont :

  • Haskell (où je commence vraiment à penser que si le code se compile, il fonctionne !)
  • Scala
  • F#

mais je peux aussi adapter mes connaissances sur les anti-modèles documentés dans d'autres langages fonctionnels.

J'ai beaucoup cherché sur le web, mais toutes les ressources que j'ai trouvées sont soit liées à la POO, soit à la disposition des fonctions (définir une variable au début de la fonction, etc...).

14voto

Rex Kerr Points 94401

Le seul anti-modèle que j'ai vu est la monadisation excessive, et comme les monades peuvent être incroyablement utiles, cela se situe quelque part entre une mauvaise pratique et un anti-modèle.

Supposons que vous ayez une propriété P que vous voulez être vrai pour certains de vos objets. Vous pouvez décorer vos objets avec une monade P (ici en Scala, utilisez paste dans le REPL pour que l'objet et son compagnon restent ensemble) :

class P[A](val value: A) {
  def flatMap[B](f: A => P[B]): P[B] = f(value)       // AKA bind, >>=
  def map[B](f: A => B) = flatMap(f andThen P.pure)   // (to keep `for` happy)
}
object P {
  def pure[A](a: A) = new P(a)                        // AKA unit, return
}

Ok, jusqu'ici tout va bien ; on a un peu triché en faisant value a val plutôt que d'en faire une comonade (si c'est ce que nous voulions), mais nous avons maintenant un emballage pratique dans lequel nous pouvons envelopper n'importe quoi. Supposons maintenant que nous ayons également des propriétés Q y R .

class Q[A](val value: A) {
  def flatMap[B](f: A => Q[B]): Q[B] = f(value)
  def map[B](f: A => B) = flatMap(f andThen Q.pure)
}
object Q {
  def pure[A](a: A) = new Q(a)
}
class R[A](val value: A) {
  def flatMap[B](f: A => R[B]): R[B] = f(value)    
  def map[B](f: A => B) = flatMap(f andThen R.pure)
}
object R {
  def pure[A](a: A) = new R(a) 
}

Nous décorons donc notre objet :

class Foo { override def toString = "foo" }
val bippy = R.pure( Q.pure( P.pure( new Foo ) ) )

Maintenant, nous sommes soudainement confrontés à une multitude de problèmes. Si nous avons une méthode qui requiert la propriété Q comment y accéder ?

def bar(qf: Q[Foo]) = qf.value.toString + "bar"

Eh bien, clairement bar(bippy) ne va pas marcher. Il y a traverse o swap qui retournent effectivement les monades, donc nous pourrions, si nous avions défini swap d'une manière appropriée, faites quelque chose comme

bippy.map(_.swap).map(_.map(bar))

pour récupérer notre chaîne (en fait, un R[P[String]] ). Mais nous nous sommes maintenant engagés à faire quelque chose comme ça pour chaque méthode que nous appelons.

C'est généralement la mauvaise chose à faire. Lorsque cela est possible, vous devez utiliser un autre mécanisme d'abstraction tout aussi sûr. Par exemple, en Scala, vous pouvez également créer des traits marqueurs

trait X
trait Y
trait Z
val tweel = new Foo with X with Y with Z
def baz(yf: Foo with Y) = yf.toString + "baz"
baz(tweel)

Ouf ! C'est tellement plus facile. Maintenant, il est très important de souligner que tout n'est pas plus facile . Par exemple, avec cette méthode, si vous commencez à manipuler Foo vous devrez garder la trace de tous les décorateurs vous-même au lieu de laisser la monadique map / flatMap le faire pour vous. Mais très souvent, vous Ne le fais pas. doivent faire un tas de manipulations en nature, et les monades profondément imbriquées sont un anti-modèle.

(Note : l'imbrication monadique a une structure de pile alors que les traits ont une structure d'ensemble ; il n'y a pas de raison inhérente pour qu'un compilateur ne puisse pas autoriser les monades de type ensemble, mais ce n'est pas une construction naturelle pour les formulations typiques de la théorie des types. L'anti-modèle est une simple conséquence du fait que les piles profondes sont difficiles à utiliser. Ils peuvent être un peu plus faciles si vous implémentez toutes les opérations de pile de Forth pour vos monades (ou l'ensemble standard de transformateurs de monades en Haskell).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X