Qu'est-ce qu'un combinateur ??
Est-ce "une fonction ou une définition sans variables libres" (comme défini sur SO)?
Ou que diriez-vous de ceci: selon John Hughes dans son article bien connu sur les flèches, "un combinateur est une fonction qui construit des fragments de programme à partir de fragments de programme" , ce qui est avantageux parce que "... le programmeur utilisant des combinateurs construit une grande partie du programme automatiquement, plutôt que d’écrire chaque détail à la main ". Il poursuit en disant que map
et filter
sont deux exemples courants de tels combinateurs.
Quelques combinateurs qui correspondent à la première définition:
- S
- K
- Oui
- d'autres de To Mock a Mockingbird (je me trompe peut-être - je n'ai pas lu ce livre)
Quelques combinateurs qui correspondent à la deuxième définition:
- carte
- filtre
- plier / réduire (vraisemblablement)
- l'un des >> =, compose, fmap ?????
Je ne suis pas intéressé par la première définition - cela ne m'aiderait pas à écrire un vrai programme (+1 si vous me convaincez que je me trompe). Veuillez m'aider à comprendre la deuxième définition . Je pense que mapper, filtrer et réduire sont utiles: ils me permettent de programmer à un niveau supérieur - moins d'erreurs, un code plus court et plus clair. Voici quelques-unes de mes questions spécifiques sur les combinateurs:
- Quels sont les autres exemples de combinateurs tels que map, filter?
- Quels combinateurs les langages de programmation implémentent-ils souvent?
- Comment les combinateurs peuvent-ils m'aider à concevoir une meilleure API?
- Comment concevoir des combinateurs efficaces?
- À quoi sont similaires les combinateurs dans un langage non fonctionnel (par exemple, Java), ou qu'utilisent ces langages à la place des combinateurs?
Mettre à jour
Grâce à @CA McCann, j'ai maintenant une meilleure compréhension des combinateurs. Mais une question reste un point de friction pour moi:
Quelle est la différence entre un programme fonctionnel écrit avec, et un autre écrit sans, une utilisation intensive de combinateurs?
Je soupçonne que la réponse est que la version lourde du combinateur est plus courte, plus claire, plus générale, mais j'apprécierais une discussion plus approfondie, si possible.
Je recherche également plus d'exemples et d'explications de combinateurs complexes (c'est-à-dire plus complexes que fold
) dans les langages de programmation courants.
la source
Réponses:
Les deux définitions sont fondamentalement la même chose. Le premier est basé sur la définition formelle et les exemples que vous donnez sont des combinateurs primitifs - les plus petits blocs de construction possibles. Ils peuvent vous aider à écrire un vrai programme dans la mesure où, avec eux, vous pouvez construire des combinateurs plus sophistiqués. Pensez aux combinateurs comme S et K comme le langage machine d'un hypothétique «ordinateur combinatoire». Les ordinateurs réels ne fonctionnent pas de cette façon, bien sûr, donc dans la pratique, vous aurez généralement des opérations de plus haut niveau implémentées dans les coulisses d'une autre manière, mais la base conceptuelle est toujours un outil utile pour comprendre la signification de ces niveaux supérieurs. opérations.
La deuxième définition que vous donnez est plus informelle et concerne l'utilisation de combinateurs plus sophistiqués, sous la forme de fonctions d'ordre supérieur qui combinent d'autres fonctions de diverses manières. Notez que si les blocs de construction de base sont les combinateurs primitifs ci-dessus, tout ce qui est construit à partir d'eux est une fonction d'ordre supérieur et un combinateur également. Dans un langage où d'autres primitives existent, cependant, vous avez une distinction entre les choses qui sont ou ne sont pas des fonctions, auquel cas un combinateur est généralement défini comme une fonction qui manipule d'autres fonctions de manière générale, plutôt que d'opérer sur des non- faire fonctionner les choses directement.
Beaucoup trop pour les énumérer! Les deux transforment une fonction qui décrit le comportement sur une valeur unique en une fonction qui décrit le comportement sur une collection entière. Vous pouvez également avoir des fonctions qui ne transforment que d' autres fonctions, telles que leur composition de bout en bout ou la division et la recombinaison d'arguments. Vous pouvez avoir des combinateurs qui transforment les opérations en une seule étape en opérations récursives qui produisent ou consomment des collections. Ou toutes sortes d'autres choses, vraiment.
Cela va beaucoup varier. Il y a relativement peu de combinateurs complètement génériques - principalement les primitifs mentionnés ci-dessus - donc dans la plupart des cas, les combinateurs auront une certaine conscience de toutes les structures de données utilisées (même si ces structures de données sont construites à partir d'autres combinateurs de toute façon), dans lesquelles cas, il y a typiquement une poignée de combinateurs "entièrement génériques" et ensuite les diverses formes spécialisées que quelqu'un a décidé de fournir. Il existe un nombre ridicule de cas où (des versions convenablement généralisées de) mapper, plier et déplier suffisent à faire presque tout ce que vous pourriez souhaiter.
Exactement comme vous l'avez dit, en pensant en termes d'opérations de haut niveau et de la manière dont celles-ci interagissent, au lieu de détails de bas niveau.
Pensez à la popularité des boucles de style «pour chaque» par rapport aux collections, qui vous permettent d'abstraire les détails de l'énumération d'une collection. Ce ne sont que des opérations de mappage / pliage dans la plupart des cas, et en en faisant un combinateur (plutôt qu'une syntaxe intégrée), vous pouvez faire des choses telles que prendre deux boucles existantes et les combiner directement de plusieurs façons - imbriquer l'une dans l'autre, faites les uns après les autres, et ainsi de suite - en appliquant simplement un combinateur, plutôt que de jongler avec tout un tas de code.
Tout d'abord, réfléchissez aux opérations qui ont du sens sur les données utilisées par votre programme. Pensez ensuite à la manière dont ces opérations peuvent être combinées de manière générique de manière significative, ainsi qu'à la manière dont les opérations peuvent être décomposées en éléments plus petits qui sont reliés entre eux. L'essentiel est de travailler avec des transformations et des opérations , pas des actions directes . Lorsque vous avez une fonction qui fait juste un peu de fonctionnalité compliquée de manière opaque et ne crache qu'une sorte de résultat pré-digéré, vous ne pouvez pas faire grand-chose avec cela. Laissez les résultats finaux au code qui utilise les combinateurs - vous voulez des choses qui vous mènent du point A au point B, pas des choses qui s'attendent à être le début ou la fin d'un processus.
Ahahahaha. C'est drôle, vous devriez demander, parce que les objets sont vraiment des choses d'ordre supérieur en premier lieu - ils ont des données, mais ils transportent également un tas d'opérations, et beaucoup de ce qui constitue une bonne conception de la POO se résume à "les objets devraient agissent généralement comme des combinateurs et non comme des structures de données ".
Donc probablement la meilleure réponse ici est qu'au lieu de choses de type combinateur, ils utilisent des classes avec beaucoup de méthodes getter et setter ou des champs publics, et une logique qui consiste principalement à faire une action opaque et prédéfinie.
la source