Composition de fonction Haskell (.) Et idiomes d'application de fonction ($): utilisation correcte

129

J'ai lu Real World Haskell , et j'approche de la fin, mais une question de style me dérange à propos des opérateurs (.)et ($).

Lorsque vous écrivez une fonction qui est une composition d'autres fonctions, vous l'écrivez comme:

f = g . h

Mais lorsque vous appliquez quelque chose à la fin de ces fonctions, je l'écris comme ceci:

k = a $ b $ c $ value

Mais le livre l'écrirait comme ceci:

k = a . b . c $ value

Maintenant, pour moi, ils semblent fonctionnellement équivalents, ils font exactement la même chose à mes yeux. Cependant, plus je regarde, plus je vois des gens écrire leurs fonctions à la manière du livre: composer avec d' (.)abord puis seulement à la fin utiliser ($)pour ajouter une valeur pour évaluer le lot (personne ne le fait avec beaucoup de compositions en dollars) .

Y a-t-il une raison d'utiliser la méthode des livres qui est bien meilleure que d'utiliser tous les ($)symboles? Ou y a-t-il des bonnes pratiques que je ne reçois pas? Ou est-ce superflu et je ne devrais pas m'inquiéter du tout?

Robert Massaioli
la source
4
Notez que le deuxième exemple peut être fait commek = a $ b $ c value
Thomas Eding
1
Oui, c'est possible, comme Zifre l'a mentionné ci-dessous, mais j'ai décidé de le laisser là car cela ne nuit à rien et rend ses commentaires (et maintenant vos) sens. Merci quand même. +1 :)
Robert Massaioli
2
Une autre approche courante est a . b $ c value, que je n'aime pas autant que le troisième exemple, mais enregistre quelques caractères.
John L

Réponses:

153

Je suppose que je peux répondre à cela par l'autorité.

Y a-t-il une raison d'utiliser la méthode des livres qui est bien meilleure que d'utiliser tous les symboles ($)?

Il n'y a pas de raison particulière. Bryan et moi préférons tous les deux réduire le bruit de ligne. .est plus silencieux que $. En conséquence, le livre utilise la f . g . h $ xsyntaxe.

Don Stewart
la source
3
Eh bien, je ne peux pas espérer une meilleure réponse que celle-ci; de l'un des auteurs lui-même. :) Et cela a du sens, cela semble beaucoup plus calme sur la page que je lis. Marquer ceci comme la réponse car cela répond directement à la question. Merci pour votre réponse; et, en fait, le livre.
Robert Massaioli
38
Je ne suis pas en désaccord avec l'auteur, mais je pense qu'il y a une autre raison plus importante dans le modèle mental de créer quelque chose plutôt que de l' utiliser . Les utilisateurs de Haskell ont plutôt tendance à vouloir penser f.g.hà une nouvelle création intelligente f(g(h())). Maintenant, ils appellent une nouvelle fonction, bien que anonyme, qu'ils ont créée plutôt que de simplement enchaîner un gros dictionnaire d'appels de fonctions préfabriqués comme un utilisateur PHP.
Evan Carroll
1
C'est une déclaration intéressante: «réduire le bruit de ligne» et «plus silencieux que». Je n'ai jamais pensé aux langages de programmation dans cette terminologie, mais c'est parfaitement logique.
Rabarberski
53

Ils sont en effet équivalents: gardez à l'esprit que l' $opérateur ne fait essentiellement rien. f $ xévalue à f x. Le but de $est son comportement de fixité: préséance associative à droite et minimale. En supprimant $et en utilisant des parenthèses pour le regroupement au lieu de la priorité infixe, les extraits de code ressemblent à ceci:

k = a (b (c (value)))

et

k = (a . b . c) value

La raison de préférer la .version à la $version est la même raison de préférer les deux à la version très entre parenthèses ci-dessus: l'attrait esthétique.

Cependant, certains pourraient se demander si l'utilisation d'opérateurs infixes au lieu de parenthèses est basée sur une envie subconsciente d'éviter toute ressemblance possible avec Lisp (je plaisante ... je pense?).

CA McCann
la source
38

Je rajouterais que f . g $ x, f . gest une unité syntaxique significative.

Pendant ce temps, en f $ g $ x, f $ gn'est pas une unité significative. Une chaîne de $est sans doute plus impérative - obtenez d' abord le résultat gde x, puis faites- fle, puis faites- foole, puis etc.

Pendant ce temps, une chaîne de .est sans doute plus déclarative et, dans un certain sens, plus proche d'une vue centrée sur le flux de données - composez une série de fonctions et, finalement, appliquez-les à quelque chose.

sclv
la source
2
J'apprends Haskell (je n'ai rien codé de significatif) mais j'aime penser à $ comme une sorte d'opérateur "pipe". C'est un peu comme le terminal | pipe (sauf les flux de données de droite à gauche), mais comme les processus terminaux, chaque unité est explicitement indépendante.
LostSalad
1
L' $opérateur semble se comporter de la même manière que l' <|opérateur en F #. Je crois que les deux sont définis de la même manière, en fait - en F # (<|) a b = a bet en Haskell a $ b = a b, qui sont essentiellement équivalents.
Tom Galvin
@Quackmatic Assez certain qu'il est (<|) b a = a ben F #, car il est utilisé comme [1; 2; 3; 4; 5] <| List.map ((+) 1)si la mémoire est bonne .
BalinKingOfMoria Reinstate CMs
@BalinKingOfMoria L' <|opérateur passe la valeur à la fonction, plutôt que de passer la fonction à la valeur - votre exemple de code fonctionnerait avec l' |>opérateur à la place.
Tom Galvin
@Quackmatic Oh. Je ne savais pas qu'il y avait plusieurs versions (je n'ai pas beaucoup utilisé F #).
BalinKingOfMoria Reinstate CMs
18

Pour moi, je pense que la réponse est (a) la propreté, comme Don l'a dit ; et (b) je trouve que lorsque j'édite du code, ma fonction peut finir dans un style sans point, et alors tout ce que j'ai à faire est de supprimer le dernier $au lieu de revenir en arrière et de tout changer. Un point mineur, certes, mais une subtilité.

Antal Spector-Zabusky
la source
Ouais c'est une bonne raison pour l'écrire comme ça, si tu veux finir par une composition de fonction alors c'est plus rapide. :) Yay pour enregistrer les frappes, mais surtout le temps. +1
Robert Massaioli
13

Il y a une discussion intéressante sur cette question sur ce fil de discussion haskell-cafe . Apparemment , il y a un point de vue minoritaire qui considère que le droit associativité $est « tout simplement faux » , et en choisissant f . g . h $ xplus f $ g $ h $ xest une façon de Esquive la question.

Travis Brown
la source
Hé, vous avez trouvé toute une discussion sur le sujet. C'est génial, j'en ai une lecture maintenant. +1
Robert Massaioli
2
Arguments similaires ici: ghc.haskell.org/trac/haskell-prime/wiki/…
enrique
Notez qu'il $!a également la bonne associativité "tout à fait faux" - Pourquoi le $! opérateur droit-associatif? .
imz - Ivan Zakharyaschev
3

C'est juste une question de style. Cependant, la façon dont le livre le fait a plus de sens pour moi. Il compose toutes les fonctions, puis l'applique à la valeur.

Votre méthode semble étrange et la dernière $est inutile.

Cependant, cela n'a vraiment pas d'importance. Dans Haskell, il existe généralement de très nombreuses façons correctes de faire la même chose.

Zifre
la source
3
Je n'ai pas remarqué que le dernier $ était inutile mais j'aurais dû. Merci et je vais en rester là pour que les gens sachent ce que signifie ce commentaire.
Robert Massaioli
0

Je sais que c'est une question très ancienne, mais je pense qu'il y a une autre raison à cela qui n'a pas été mentionnée.

Si vous déclarez une nouvelle fonction sans point f . g . h, la valeur que vous transmettez sera automatiquement appliquée. Cependant, si vous écrivez f $ g $ h, cela ne fonctionnera pas.

Je pense que la raison pour laquelle l'auteur préfère la méthode de composition est qu'elle conduit à une bonne pratique de création de fonctions.

hackeryarn
la source