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.
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.
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)
hat keinen Eingang und kann daher nicht mit dem Operator .
verwendet werden.show
kann ein Int
annehmen und einen String
zurückgeben.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
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?
@CodexArcanum In diesem Beispiel wäre etwas wie putStrLn . show . (+1) $ 1
äquivalent. Sie haben recht, dass die meisten (alle?) Infix-Operatoren Funktionen sind.
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.
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.
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)
"Beachte, dass ich absichtlich zusätzliche Klammern in der Typensignatur hinzugefügt habe." Ich bin verwirrt... warum hast du das gemacht?
@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.
($)
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"
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.