web-dev-qa-db-fra.com

Que sont les combinateurs et comment sont-ils appliqués aux projets de programmation? (explication pratique)

Que sont les combinateurs?

Je cherche:

  • une explication pratique
  • des exemples d'utilisation
  • exemples de la façon dont les combinateurs améliorent la qualité/généralité du code

Je ne cherche pas:

  • explications des combinateurs qui ne m'aident pas à faire le travail (comme le combinateur Y)
53
user39685

D'un point de vue pratique, les combinateurs sont une sorte de constructions de programmation qui vous permettent de rassembler des éléments de logique de manières intéressantes et souvent avancées. Leur utilisation dépend généralement de la possibilité de pouvoir compresser du code exécutable dans des objets, souvent appelés (pour des raisons historiques) des fonctions lambda ou des expressions lambda, mais votre kilométrage peut varier.

Un exemple simple de combinateur (utile) est celui qui prend deux fonctions lambda sans paramètres et en crée une nouvelle qui les exécute en séquence. Le combinateur réel ressemble à un pseudocode générique comme ceci:

func in_sequence(first, second):
  lambda ():
    first()
    second()

La chose cruciale qui en fait un combinateur est la fonction anonyme (fonction lambda) sur la deuxième ligne; quand vous appelez

a = in_sequence(f, g)

l'objet résultant a est pas le résultat de l'exécution en premier f() puis g (), mais c'est un objet que vous pouvez appeler plus tard pour exécuter f() et g() dans l'ordre:

a() // a is a callable object, i.e. a function without parameters

Vous pouvez également avoir un combinateur qui exécute deux blocs de code en parallèle:

func in_parallel(first, second):
  lambda ():
    t1 = start_thread(first)
    t2 = start_thread(second)
    wait(t1)
    wait(t2)

Et encore une fois,

a = in_parallel(f, g)
a()

Ce qui est cool, c'est que 'in_parallel' et 'in_sequence' sont tous les deux des combinateurs avec le même type/signature, c'est-à-dire qu'ils prennent tous deux deux objets de fonction sans paramètre et en retournent un nouveau. Vous pouvez alors écrire des choses comme

a = in_sequence(in_parallel(f, g), in_parallel(h, i))

et cela fonctionne comme prévu.

Fondamentalement, les combinateurs vous permettent de construire le flux de contrôle de votre programme (entre autres) d'une manière procédurale et flexible. Par exemple, si vous utilisez le combinateur in_parallel (..) pour exécuter le parallélisme dans votre programme, vous pouvez ajouter le débogage lié à cela à l'implémentation du combinateur in_parallel lui-même. Plus tard, si vous pensez que votre programme contient un bogue lié au parallélisme, vous pouvez en fait simplement réimplémenter in_parallel:

in_parallel(first, second):
  in_sequence(first, second)

et d'un seul coup, toutes les sections parallèles ont été converties en sections séquentielles!

Les combinateurs sont très utiles lorsqu'ils sont utilisés correctement.

Le Y Combinator, cependant, n'est pas nécessaire dans la vraie vie. C'est un combinateur qui vous permet de créer des fonctions auto-récursives, et vous pouvez les créer facilement dans n'importe quel langage moderne sans le Y Combinator.

56
antti.huima

Il est faux de considérer Y-combinator comme quelque chose qui "n'aidera pas à faire le travail". Je l'ai trouvé très utile à plusieurs reprises. Le cas le plus évident est celui où vous devez rapidement bootstrap un langage interprété incorporé. Si vous fournissez un ensemble minimal de primitives, à savoir sequence, select, call, const et un closure allocation, c'est déjà suffisant pour construire un langage complet, arbitraire et complexe. Aucun support spécial pour la récursivité n'est nécessaire - il peut être ajouté via un combinateur à point fixe. Sinon, vous aurez besoin de primitives beaucoup plus compliquées.

Un autre cas évident pour les combinateurs est l'obfuscation. Un code traduit dans le calcul SKI est pratiquement illisible. Si vous devez vraiment masquer une implémentation d'un algorithme, pensez à utiliser des combinateurs, voici un exemple .

Et, bien sûr, les combinateurs sont un outil important pour la mise en œuvre de langages fonctionnels. L'approche la plus simple (comme dans l'exemple ci-dessus) est via SKI ou un calcul équivalent. Supercombinators sont utilisés dans certaines autres implémentations. Ce livre en parle en profondeur.

C'est une blague , mais une blague mérite une lecture très attentive, car de nombreuses théories et techniques de programmation obscures y sont couvertes.

10
SK-logic

En fouillant un peu, j'ai trouvé une question StackOverflow, Bonne explication de "Combinators" (Pour les non mathématiciens) c'est un proche cousin de cette question. L'une des réponses pointait vers le blog de Reginald Braithwaite, Homoiconic , qui renvoie à plusieurs exemples utiles de combinateurs dans le code (par exemple le combinateur K , implémenté par Ruby's Object#tap méthode - lisez la page pour savoir pourquoi elle est utile).

La page Wikipedia sur la logique combinatoire décrit les combinateurs de manière plus globale.

8
Aidan Cully