102 votes

Composition Haskell (.) contre l'opérateur pipe forward de F# (|>)

En F#, utilisation de l'opérateur pipe-forward, |> est assez courante. Cependant, en Haskell, je n'ai jamais vu de composition de fonctions, (.) qui sont utilisés. Je comprends qu'ils sont connexe Mais y a-t-il une raison linguistique pour laquelle le pipe-forward n'est pas utilisé en Haskell ou est-ce autre chose ?

2 votes

réponse de Lihanseys déclare que & est le |> . Enterré profondément dans ce fil et il m'a fallu quelques jours pour le découvrir. Je l'utilise beaucoup, car vous lisez naturellement de gauche à droite pour suivre votre code.

87voto

Ganesh Sittampalam Points 17695

En fa# (|>) est important en raison de la vérification des caractères de gauche à droite. Par exemple :

List.map (fun x -> x.Value) xs

ne vérifie généralement pas le type, car même si le type de l'élément xs est connu, le type de l'argument x à la lambda n'est pas connue au moment où le contrôleur de type la voit, donc il ne sait pas comment résoudre x.Value .

En revanche

xs |> List.map (fun x -> x.Value)

fonctionnera bien, car le type de xs conduira au type de x être connu.

La vérification du type de gauche à droite est nécessaire en raison de la résolution de nom impliquée dans des constructions telles que x.Value . Simon Peyton Jones a écrit un proposition pour ajouter un type similaire de résolution de nom à Haskell, mais il suggère d'utiliser des contraintes locales pour savoir si un type supporte une opération particulière ou non. Ainsi, dans le premier exemple, l'exigence selon laquelle x a besoin d'un Value les biens seraient reportés jusqu'à xs a été vu et cette exigence a pu être résolue. Cela complique toutefois le système de types.

1 votes

Ce qui est intéressant, c'est qu'il existe un opérateur (<|) similaire à (.) en Haskell avec la même direction des données de droite à gauche. Mais comment fonctionnera la résolution de type pour cet opérateur ?

7 votes

(<|) est en fait similaire à celui de Haskell ($). La vérification du type de gauche à droite n'est nécessaire que pour résoudre des éléments tels que .Value, donc (<|) fonctionne bien dans d'autres scénarios, ou si vous utilisez des annotations de type explicites.

62voto

Brian Points 82719

Je suis un peu spéculatif...

Culture : Je pense |> est un opérateur important dans la "culture" F#, et peut-être de façon similaire avec . pour Haskell. F# possède un opérateur de composition de fonctions << mais je pense que la communauté F# a tendance à utiliser style sans points moins que la communauté Haskell.

Différences linguistiques : Je ne connais pas assez les deux langages pour comparer, mais peut-être que les règles de généralisation des let-bindings sont suffisamment différentes pour affecter cela. Par exemple, je sais qu'en F#, il est parfois possible d'écrire

let f = exp

ne compilera pas, et vous aurez besoin d'une conversion explicite en eta :

let f x = (exp) x   // or x |> exp

pour le faire compiler. Cela éloigne également les gens du style sans points/compositionnel, et les oriente vers le style pipelining. De plus, l'inférence de type F# exige parfois le pipelining, de sorte qu'un type connu apparaisse à gauche (cf. aquí ).

(Personnellement, je trouve le style sans points illisible, mais je suppose que toute chose nouvelle/différente semble illisible jusqu'à ce qu'on s'y habitue).

Je pense que les deux sont potentiellement viables dans l'une ou l'autre langue, et l'histoire/culture/accident peut définir pourquoi chaque communauté s'est installée à un "attracteur" différent.

7 votes

Je suis d'accord avec les différences culturelles. Le Haskell traditionnel fait usage de . y $ Les gens continuent donc à les utiliser.

9 votes

Le point libre est parfois plus lisible que le pointu, parfois moins. Je l'utilise généralement dans l'argument de fonctions comme map et filter, pour éviter qu'une lambda ne vienne encombrer les choses. Je l'utilise aussi parfois dans les fonctions de haut niveau, mais moins souvent et seulement quand il s'agit de quelque chose de simple.

2 votes

Je n'y vois pas beaucoup de culture, dans le sens où il n'y a tout simplement pas beaucoup de choix en la matière en ce qui concerne F# (pour les raisons que vous et Ganesh mentionnez). Je dirais donc que les deux sont viables en Haskell, mais que F# est définitivement bien mieux équipé pour utiliser l'opérateur pipeline.

46voto

Nathan Sanders Points 10641

Encore des spéculations, cette fois du côté de Haskell principalement...

($) est le retournement de (|>) et son utilisation est assez courante lorsqu'il est impossible d'écrire du code sans points. Ainsi, la principale raison pour laquelle (|>) non utilisé en Haskell est que sa place est déjà prise par ($) .

De plus, avec un peu d'expérience de F#, je pense que (|>) est si populaire dans le code F# parce qu'il ressemble à la fonction Subject.Verb(Object) structure de l'OO. Puisque F# vise une intégration fonctionnelle/OO en douceur, Subject |> Verb Object est une transition assez douce pour les nouveaux programmeurs fonctionnels.

Personnellement, j'aime penser de gauche à droite aussi, donc j'utilise (|>) en Haskell, mais je ne pense pas que beaucoup d'autres personnes le fassent.

0 votes

Bonjour Nathan, est-ce que "flip ($)" est prédéfini quelque part dans la plateforme Haskell ? Le nom "(|>)" est déjà défini dans Data.Sequence avec une autre signification. S'il n'est pas déjà défini, comment l'appelez-vous ? Je pense aller avec "($>) = flip ($)".

2 votes

@mattbh : Pas que je puisse trouver avec Hoogle. Je ne connaissais pas Data.Sequence.|> pero $> Il semble raisonnable d'éviter les conflits à cet endroit. Honnêtement, il n'y a qu'un nombre limité de bons opérateurs, donc j'utiliserais simplement |> pour les deux et gérer les conflits au cas par cas. (Je serais également tenté de simplement aliaser Data.Sequence.|> como snoc )

0 votes

($) redéfinit simplement l'associativité de l'analyse syntaxique. Ce n'est pas la même chose que la composition directe -- vous devez avoir des noms liés dans la portée. Essayez vous-même : pastebin.com/uEc2k612

32voto

AshleyF Points 1634

Je pense que nous confondons les choses. La méthode Haskell ( . ) est équivalent à celui de F# ( >> ). À ne pas confondre avec les F# ( |> ) qui n'est qu'une application de fonction inversée et qui est semblable à l'application ( $ ) - inversé :

let (>>) f g x = g (f x)
let (|>) x f = f x

Je crois que les programmeurs Haskell utilisent $ souvent. Peut-être pas aussi souvent que les programmeurs F# ont tendance à utiliser |> . D'autre part, certains utilisateurs de F# utilisent >> à un degré ridicule : http://blogs.msdn.com/b/ashleyf/archive/2011/04/21/programming-is-pointless.aspx

3 votes

Comme vous le dites, c'est comme la méthode Haskell $ opérateur - inversé, vous pouvez aussi le définir facilement comme : a |> b = flip ($) qui devient équivalent au pipeline de F#, par exemple vous pouvez alors faire [1..10] |> map f

8 votes

Je pense ( . ) la même chose que ( << ), tandis que ( >> ) est la composition inverse. C'est-à-dire ( >> ) : ('T1 -> 'T2) -> ('T2 -> 'T3) -> 'T1 -> 'T3 vs ( << ) : ('T2 -> 'T3) -> ('T1 -> 'T2) -> 'T1 -> 'T3

0 votes

-1 pour "utiliser >> à un degré ridicule". (Enfin, je ne l'ai pas fait, mais vous avez compris). F dans F# est pour "fonctionnel", donc la composition de fonctions est légitime.

17voto

spookylukey Points 2249

J'ai vu >>> utilisé pour flip (.) Je l'utilise souvent moi-même, en particulier pour les longues chaînes qui se comprennent mieux de gauche à droite.

>>> provient en fait de Control.Arrow, et fonctionne sur plus que de simples fonctions.

0 votes

>>> est défini dans Control.Category .

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