804 Stimmen

Was ist der Unterschied zwischen . (Punkt) und $ (Dollarzeichen)?

Was ist der Unterschied zwischen dem Punkt (.) und dem Dollarzeichen ($)?

Wie ich es sehe, sind sie beide syntaktischer Zucker, um Klammern nicht verwenden zu müssen.

1364voto

Michael Steele Punkte 14992

Der Operator $ dient dazu, Klammern zu vermeiden. Alles, was nach ihm erscheint, hat Vorrang vor allem, was davor steht.

Zum Beispiel, nehmen wir an, du hast eine Zeile, die lautet:

putStrLn (show (1 + 1))

Wenn du diese Klammern loswerden willst, würde eine dieser Zeilen dasselbe bewirken:

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

Der Hauptzweck des Operators . ist nicht, Klammern zu vermeiden, sondern Funktionen zu verketten. Er ermöglicht es dir, die Ausgabe von dem, was rechts erscheint, mit dem Eingang von dem, was links erscheint, zu verbinden. Das führt normalerweise auch zu weniger Klammern, funktioniert aber anders.

Gehen wir zurück zu demselben Beispiel:

putStrLn (show (1 + 1))
  1. (1 + 1) hat keinen Eingang und kann daher nicht mit dem Operator . verwendet werden.
  2. show kann ein Int annehmen und einen String zurückgeben.
  3. putStrLn kann einen String annehmen und ein IO () zurückgeben.

Du kannst show an putStrLn so verknüpfen:

(putStrLn . show) (1 + 1)

Wenn dir das zu viele Klammern sind, kannst du sie mit dem Operator $ loswerden:

putStrLn . show $ 1 + 1

74 Stimmen

Eigentlich ist + auch eine Funktion, könntest du es nicht auch präfix verwenden und dann zusammenstellen, wie `putStrLn . show . (+) 1 1`? Nicht dass es klarer wäre, aber ich meine... du könntest es, richtig?

9 Stimmen

@CodexArcanum In diesem Beispiel wäre etwas wie putStrLn . show . (+1) $ 1 äquivalent. Sie haben recht, dass die meisten (alle?) Infix-Operatoren Funktionen sind.

0 Stimmen

Nachdem ich putStrLn $ show $ 1 + 1 gesehen habe, denke ich ehrlich gesagt, dass $ durch ein leichteres Zeichen ersetzt werden muss. Ich kann im Moment an kein passendes denken, weil alle bereits benutzt sind, aber irgendwann wird ein passendes Zeichen auftauchen.

216voto

Sie haben verschiedene Arten und verschiedene Definitionen:

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

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

($) ist dazu gedacht, die normale Funktionsanwendung zu ersetzen, aber mit einer anderen Priorität, um Klammern zu vermeiden. (.) dient dazu, zwei Funktionen zu verketten, um eine neue Funktion zu erzeugen.

In einigen Fällen sind sie austauschbar, aber das gilt nicht allgemein. Das typische Beispiel, in dem sie austauschbar sind, ist:

f $ g $ h $ x

\==>

f . g . h $ x

Mit anderen Worten: In einer Kette von $s kann alles außer dem letzten durch . ersetzt werden.

3 Stimmen

Was wäre, wenn x eine Funktion wäre? Könntest du dann . als die letzte verwenden?

4 Stimmen

@richizy wenn du tatsächlich x in diesem Kontext anwendest, dann ja - aber dann würde das "endgültige" auf etwas anderes als x angewendet werden. Wenn du x nicht anwendest, dann ist es kein Unterschied, ob x ein Wert ist.

137voto

Martijn Punkte 6645

Beachten Sie auch, dass ($) die Identitätsfunktion ist, die auf Funktionstypen spezialisiert ist. Die Identitätsfunktion sieht so aus:

id :: a -> a
id x = x

Während ($) so aussieht:

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

Beachten Sie, dass ich absichtlich zusätzliche Klammern in der Typsignatur hinzugefügt habe.

Verwendungen von ($) können normalerweise durch Hinzufügen von Klammern eliminiert werden (außer wenn der Operator in einem Abschnitt verwendet wird). Zum Beispiel: f $ g x wird zu f (g x).

Verwendungen von (.) sind oft etwas schwieriger zu ersetzen; sie benötigen normalerweise ein Lambda oder die Einführung eines expliziten Funktionsparameters. Zum Beispiel:

f = g . h

wird zu

f x = (g . h) x

wird zu

f x = g (h x)

1 Stimmen

"Beachte, dass ich absichtlich zusätzliche Klammern in der Typensignatur hinzugefügt habe." Ich bin verwirrt... warum hast du das gemacht?

11 Stimmen

@MateenUlhaq Der Typ von ($) ist (a -> b) -> a -> b, was dasselbe ist wie (a -> b) -> (a -> b), aber die zusätzlichen Klammern fügen hier etwas Klarheit hinzu.

5 Stimmen

Oh, ich glaube schon. Ich habe daran gedacht als eine Funktion von zwei Argumenten... aber aufgrund von Currying ist es genau äquivalent zu einer Funktion, die eine Funktion zurückgibt.

84voto

softmechanics Punkte 949

($) ermöglicht es, Funktionen verkettet zu verwenden, ohne Klammern hinzuzufügen, um die Auswertungsreihenfolge zu steuern:

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

Prelude> head $ tail "asdf"
's'

Der Kompositionsoperator (.) erstellt eine neue Funktion, ohne die Argumente anzugeben:

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

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

Das obige Beispiel zeigt zwar die Verwendung von Komposition, veranschaulicht jedoch nicht wirklich den Komfort. Hier ist eine weitere Analogie:

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

Wenn wir third nur einmal verwenden, können wir es vermeiden, ihm einen Namen zu geben, indem wir ein Lambda verwenden:

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

Zu guter Letzt ermöglicht uns die Komposition, das Lambda zu vermeiden:

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

7 Stimmen

Wenn das Stackoverflow eine Kombinationsfunktion hätte, würde ich die Antwort bevorzugen, die die beiden vorherigen Erklärungen mit dem Beispiel in dieser Antwort kombiniert.

62voto

ellisbben Punkte 6232

Die kurze und prägnante Version:

  • ($) ruft die Funktion auf, die ihr Argument auf der linken Seite ist, mit dem Wert auf, der ihr Argument auf der rechten Seite ist.
  • (.) komponiert die Funktion, die ihr Argument auf der linken Seite ist, mit der Funktion, die ihr Argument auf der rechten Seite ist.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X