Question Quelle est la différence entre . (point) et $ (signe dollar)?


Quelle est la différence entre le point (.) et le signe du dollar ($)? Si je comprends bien, ils sont tous les deux sucre syntaxique pour ne pas avoir besoin d'utiliser des parenthèses.


607
2018-06-02 16:06


origine


Réponses:


le $ l'opérateur est pour éviter les parenthèses. Tout ce qui apparaît après aura préséance sur tout ce qui précède.

Par exemple, disons que vous avez une ligne qui dit:

putStrLn (show (1 + 1))

Si vous voulez vous débarrasser de ces parenthèses, l'une des lignes suivantes ferait aussi la même chose:

putStrLn (show $ 1 + 1)
putStrLn $ show (1 + 1)
putStrLn $ show $ 1 + 1

L'objectif principal de la . L'opérateur n'est pas d'éviter les parenthèses, mais de chaîner les fonctions. Il vous permet de lier la sortie de tout ce qui apparaît sur la droite à l'entrée de tout ce qui apparaît sur la gauche. Cela entraîne également généralement moins de parenthèses, mais fonctionne différemment.

Pour en revenir au même exemple:

putStrLn (show (1 + 1))
  1. (1 + 1) n'a pas d'entrée, et ne peut donc pas être utilisé avec . opérateur.
  2. show peut prendre un Int et renvoyer un String.
  3. putStrLn peut prendre un String et renvoyer un IO ().

Vous pouvez enchaîner show à putStrLn comme ça:

(putStrLn . show) (1 + 1)

Si c'est trop de parenthèses à votre goût, se débarrasser d'eux avec le $ opérateur:

putStrLn . show $ 1 + 1

1091
2017-08-17 22:01



Ils ont différents types et différentes définitions:

infixr 9 .
(.) :: (b -> c) -> (a -> b) -> (a -> c)
(f . g) x = f (g x)

infixr 0 $
($) :: (a -> b) -> a -> b
f $ x = f x

($) est destiné à remplacer l'application de la fonction normale mais à une priorité différente pour éviter les parenthèses. (.) est de composer deux fonctions ensemble pour faire une nouvelle fonction.

Dans certains cas, ils sont interchangeables, mais ce n'est pas vrai en général. L'exemple typique où ils sont est:

f $ g $ h $ x

==>

f . g . h $ x

En d'autres termes dans une chaîne de $s, tous sauf le dernier peut être remplacé par .


170
2018-06-02 16:14



Notez également que ($) est la fonction d'identité spécialisée pour les types de fonctions. La fonction d'identité ressemble à ceci:

id :: a -> a
id x = x

Tandis que ($) ressemble à ça:

($) :: (a -> b) -> (a -> b)
($) = id

Notez que j'ai intentionnellement ajouté des parenthèses supplémentaires dans la signature de type.

Utilisations de ($) peut généralement être éliminé en ajoutant des parenthèses (sauf si l'opérateur est utilisé dans une section). Par exemple.: f $ g x devient f (g x).

Utilisations de (.) sont souvent un peu plus difficiles à remplacer; ils ont généralement besoin d'un lambda ou de l'introduction d'un paramètre de fonction explicite. Par exemple:

f = g . h

devient

f x = (g . h) x

devient

f x = g (h x)

J'espère que cela t'aides!


111
2018-06-02 16:32



($) permet de chaîner des fonctions sans ajouter de parenthèses pour contrôler l'ordre d'évaluation:

Prelude> head (tail "asdf")
's'

Prelude> head $ tail "asdf"
's'

L'opérateur de composition (.) crée une nouvelle fonction sans spécifier les arguments:

Prelude> let second x = head $ tail x
Prelude> second "asdf"
's'

Prelude> let second = head . tail
Prelude> second "asdf"
's'

L'exemple ci-dessus est sans doute illustratif, mais ne montre pas vraiment la commodité d'utiliser la composition. Voici une autre analogie:

Prelude> let third x = head $ tail $ tail x
Prelude> map third ["asdf", "qwer", "1234"]
"de3"

Si on n'utilise qu'une troisième fois, on peut éviter de le nommer en utilisant un lambda:

Prelude> map (\x -> head $ tail $ tail x) ["asdf", "qwer", "1234"]
"de3"

Enfin, la composition nous permet d'éviter le lambda:

Prelude> map (head . tail . tail) ["asdf", "qwer", "1234"]
"de3"

68
2018-01-07 01:43



La version courte et douce:

  • ($) appelle la fonction qui est son argument de gauche sur la valeur qui est son argument de droite.
  • (.) compose la fonction qui est son argument de gauche sur la fonction qui est son argument de droite.

57
2018-06-10 20:11



Une application utile et qui m'a pris du temps pour me rendre compte de la très courte description à vous apprendre un haskell: Depuis:

f $ x = f x

et entre parenthèses le côté droit d'une expression contenant un opérateur infixe le convertit en une fonction de préfixe, on peut écrire ($ 3) (4+) analogue à (++", world") "hello".

Pourquoi quelqu'un ferait-il cela? Pour les listes de fonctions, par exemple. Tous les deux:

map (++", world") ["hello","goodbye"]`

et:

map ($ 3) [(4+),(3*)]

sont plus courts que map (\x -> x ++ ", world") ... ou map (\f -> f 3) .... Évidemment, ces dernières variantes seraient plus lisibles pour la plupart des gens.


28
2018-01-31 12:12



... ou vous pourriez éviter le . et $ constructions en utilisant pipelining:

third xs = xs |> tail |> tail |> head

C'est après que vous avez ajouté dans la fonction d'assistance:

(|>) x y = y x

12
2017-12-04 10:24



Une excellente façon d'en apprendre plus sur n'importe quoi (n'importe quelle fonction) est de se rappeler que tout est une fonction! Ce mantra général aide, mais dans des cas spécifiques comme les opérateurs, cela aide à se souvenir de ce petit truc:

:t (.)
(.) :: (b -> c) -> (a -> b) -> a -> c

et

:t ($)
($) :: (a -> b) -> a -> b

N'oubliez pas d'utiliser :t libéralement, et envelopper vos opérateurs dans ()!


11
2018-04-15 06:10