it-swarm.dev

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

Was ist der Unterschied zwischen dem Punkt (.) und dem Dollarzeichen ($) ?. Soweit ich es verstehe, sind sie beide syntaktischer Zucker, da sie keine Klammern verwenden müssen.

643
Rabarberski

Der $-Operator dient zum Vermeiden von Klammern. Alles, was danach erscheint, hat Vorrang vor dem, was vorher kommt.

Nehmen wir zum Beispiel an, Sie haben eine Zeile, die lautet:

putStrLn (show (1 + 1))

Wenn Sie diese Klammern loswerden möchten, würde eine der folgenden Zeilen dasselbe tun:

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

Der .-Operator hat nicht zum Ziel, Klammern zu vermeiden, sondern Funktionen zu verketten. Damit können Sie die Ausgabe von rechts auf der rechten Seite mit der Eingabe von links verknüpfen. Dies führt in der Regel auch zu weniger Klammern, funktioniert jedoch anders.

Gehen wir zurück zum selben Beispiel:

putStrLn (show (1 + 1))
  1. (1 + 1) hat keine Eingabe und kann daher nicht mit dem .-Operator verwendet werden.
  2. show kann ein Int nehmen und ein String zurückgeben.
  3. putStrLn kann ein String nehmen und eine IO () zurückgeben.

Sie können show mit putStrLn folgendermaßen verketten:

(putStrLn . show) (1 + 1)

Wenn das zu viele Klammern für Sie sind, entfernen Sie sie mit dem Operator $:

putStrLn . show $ 1 + 1
1134
Michael Steele

Sie haben unterschiedliche Typen und unterschiedliche 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

($) soll die normale Funktionsanwendung ersetzen, jedoch mit einer anderen Priorität, um Klammern zu vermeiden. Mit (.) können Sie zwei Funktionen zusammenstellen, um eine neue Funktion zu erstellen.

In einigen Fällen sind sie austauschbar, dies trifft jedoch im Allgemeinen nicht zu. Das typische Beispiel, wo sie sind, ist:

f $ g $ h $ x

==>

f . g . h $ x

Mit anderen Worten, in einer Kette von $s können alle außer dem letzten durch . ersetzt werden.

175

Beachten Sie auch, dass ($) die auf Funktionstypen spezialisierte Identitätsfunktion ist. Die Identitätsfunktion sieht folgendermaßen 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 die Typensignatur eingefügt habe.

Die Verwendung von ($) kann normalerweise durch das Hinzufügen von Klammern eliminiert werden (sofern der Operator nicht in einem Abschnitt verwendet wird). Beispiel: f $ g x wird f (g x)

Die Verwendung von (.) ist oft etwas schwieriger zu ersetzen. Sie benötigen normalerweise ein Lambda oder die Einführung eines expliziten Funktionsparameters. Zum Beispiel:

f = g . h

wird

f x = (g . h) x

wird

f x = g (h x)

Hoffe das hilft!

117
Martijn

Mit ($) können Funktionen miteinander verkettet werden, ohne dass die Auswertungsreihenfolge durch Klammern ergänzt wird:

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

Prelude> head $ tail "asdf"
's'

Der Compose-Operator (.) 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 ist wohl illustrativ, zeigt aber nicht die Bequemlichkeit der Verwendung von Kompositionen. 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, es mit einem Lambda zu benennen:

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

Schließlich lässt die Komposition das Lambda vermeiden:

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

Die kurze und süße Version:

  • ($) ruft die Funktion auf, deren linkes Argument der Wert ist, das sein rechtes Argument ist.
  • (.) setzt die Funktion, die ihr linkes Argument ist, auf die Funktion, die ihr rechtes Argument ist.
58
ellisbben

Eine Anwendung, die nützlich ist und mich etwas Zeit brauchte, um aus der sehr kurzen Beschreibung herauszufinden bei lernen Sie eine Haschel : Seit:

f $ x = f x

und die rechte Seite eines Ausdrucks, der einen Infixoperator enthält, durch Klammern in eine Präfixfunktion konvertiert, kann ($ 3) (4+) analog zu (++", world") "hello" geschrieben werden.

Warum sollte jemand das tun? Zum Beispiel für Funktionslisten. Beide:

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

und:

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

sind kürzer als map (\x -> x ++ ", world") ... oder map (\f -> f 3) .... Offensichtlich sind die letzteren Varianten für die meisten Menschen lesbarer.

29
Christoph

... oder Sie könnten die Konstruktionen . und $ vermeiden, indem Sie pipelining verwenden:

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

Das ist, nachdem Sie die Hilfsfunktion hinzugefügt haben:

(|>) x y = y x
12
user1721780

Meine Regel ist einfach (ich bin auch Anfänger): 

  • verwenden Sie nicht ., wenn Sie den Parameter übergeben möchten (Aufruf der Funktion) und 
  • verwenden Sie $ nicht, wenn noch kein Parameter vorhanden ist (Funktion erstellen).

Das ist 

show $ head [1, 2]

aber nie:

show . head [1, 2]
11
halacsy

Eine gute Möglichkeit, mehr über alles (jede Funktion) zu lernen, ist, daran zu denken, dass alles eine Funktion ist! Dieses allgemeine Mantra hilft, aber in bestimmten Fällen wie Operatoren hilft es, sich an diesen kleinen Trick zu erinnern:

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

und

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

Denken Sie daran, :t großzügig zu verwenden, und wickeln Sie Ihre Operatoren in () ein!

11
lol

Haskell: Differenz zwischen . (Punkt) und $ (Dollarzeichen)

Was ist der Unterschied zwischen dem Punkt (.) und dem Dollarzeichen ($) ?. Soweit ich es verstehe, sind sie beide syntaktischer Zucker, da sie keine Klammern verwenden müssen.

Sie sind nicht syntaktischer Zucker, da keine Klammern verwendet werden müssen - sie sind Funktionen, - infixiert, daher können wir sie Operatoren nennen. 

Compose, (.) und wann es zu verwenden ist.

(.) ist die Erstellungsfunktion. So 

result = (f . g) x

entspricht dem Erstellen einer Funktion, die das Ergebnis ihres an g übergebenen Arguments an f weitergibt.

h = \x -> f (g x)
result = h x

Verwenden Sie (.), wenn Sie keine Argumente zur Verfügung haben, die an die Funktionen übergeben werden sollen, die Sie erstellen möchten. 

Rechtsassoziativ gelten ($) und wann es zu verwenden ist

($) ist eine rechtsassoziative Anwendungsfunktion mit niedriger Bindungspriorität. Es berechnet also nur die Dinge rechts davon. Somit, 

result = f $ g x

ist das gleiche wie dieses, verfahrenstechnisch (was wichtig ist, da Haskell faul bewertet wird, beginnt es zuerst, f auszuwerten):

h = f
g_x = g x
result = h g_x

oder genauer:

result = f (g x)

Verwenden Sie ($), wenn Sie alle auszuwertenden Variablen haben, bevor Sie die vorhergehende Funktion auf das Ergebnis anwenden.

Wir können dies durch Lesen der Quelle für jede Funktion sehen.

Lesen Sie die Quelle

Hier ist der source für (.):

-- | Function composition.
{-# INLINE (.) #-}
-- Make sure it has TWO args only on the left, so that it inlines
-- when applied to two functions, even if there is no final argument
(.)    :: (b -> c) -> (a -> b) -> a -> c
(.) f g = \x -> f (g x)

Und hier ist die source für ($):

-- | Application operator.  This operator is redundant, since ordinary
-- application @(f x)@ means the same as @(f '$' x)@. However, '$' has
-- low, right-associative binding precedence, so it sometimes allows
-- parentheses to be omitted; for example:
--
-- >     f $ g $ h x  =  f (g (h x))
--
-- It is also useful in higher-order situations, such as @'map' ('$' 0) [email protected],
-- or @'Data.List.zipWith' ('$') fs [email protected]
{-# INLINE ($) #-}
($)                     :: (a -> b) -> a -> b
f $ x                   =  f x

Fazit

Verwenden Sie die Komposition, wenn Sie die Funktion nicht sofort bewerten müssen. Vielleicht möchten Sie die Funktion, die sich aus der Komposition ergibt, an eine andere Funktion übergeben.

Verwenden Sie die Anwendung, wenn Sie alle Argumente zur vollständigen Bewertung angeben.

Für unser Beispiel wäre dies semantisch vorzuziehen

f $ g x

wenn wir x (oder vielmehr gs Argumente) haben, und tun Sie:

f . g

wenn wir es nicht tun.

8
Aaron Hall

Alle anderen Antworten sind ziemlich gut. Es gibt jedoch ein wichtiges Verwendungsdetail, wie ghc $ behandelt, was der ghc-Type-Checker für die Einführung in höherrangige/quantifizierte Typen ermöglicht. Wenn Sie sich zum Beispiel den Typ von $ id anschauen, werden Sie feststellen, dass er eine Funktion verwenden wird, deren Argument selbst eine polymorphe Funktion ist. Solche kleinen Dinge sind bei einem gleichwertigen Störungsoperator nicht die gleiche Flexibilität. (Ich wundere mich tatsächlich, ob $! Die gleiche Behandlung verdient oder nicht.)

Ich denke, ein kurzes Beispiel, wo Sie . und nicht $ verwenden würden, würde die Dinge klären.

double x = x * 2
triple x = x * 3
times6 = double . triple

:i times6
times6 :: Num c => c -> c

Beachten Sie, dass times6 eine Funktion ist, die aus der Funktionskomposition erstellt wird.

0
Brennan Cheung