Frage

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

Soweit ich weiß, handelt es sich bei beiden um syntaktischen Zucker, da keine Klammern verwendet werden müssen.

War es hilfreich?

Lösung

Der $ Operator Klammern zu vermeiden. Alles, was nach dem Erscheinen Vorrang vor irgendetwas nehmen, die vor kommen.

Zum Beispiel, sagen wir, Sie eine Linie haben, die lautet:

putStrLn (show (1 + 1))

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

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

Der primäre Zweck des . Betreibers ist nicht Klammern zu vermeiden, aber zu Kettenfunktionen. Damit können Sie die Ausgabe von binden, was auch immer auf der rechten Seite mit dem Eingang erscheint von was auch immer auf der linken Seite erscheint. Diese Regel führt auch zu weniger Klammern, aber anders funktioniert.

Gehen wir zurück zu dem gleichen Beispiel:

putStrLn (show (1 + 1))
  1. (1 + 1) hat keinen Eingang, und kann daher nicht mit dem . Operator verwendet werden.
  2. show kann eine Int nehmen und eine String zurück.
  3. putStrLn kann eine String nehmen und eine IO () zurück.

Sie können Kette show putStrLn wie folgt aus:

(putStrLn . show) (1 + 1)

Wenn das zu viele Klammern für Ihre Bedürfnisse anpassen, loszuwerden von ihnen mit dem $ Operator:

putStrLn . show $ 1 + 1

Andere Tipps

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

($) sollten normale Funktion Anwendung ersetzen, sondern an einem anderen Vorrang helfen Klammern zu vermeiden. (.) ist für das Komponieren zwei Funktionen zusammen, um eine neue Funktion zu machen.

In einigen Fällen sind sie austauschbar, aber dies ist in der Regel nicht wahr. Das typische Beispiel, wo sie sind, ist:

f $ g $ h $ x

==>

f . g . h $ x

Mit anderen Worten: in einer Kette von $s, alle bis auf das letzte kann man durch . ersetzt werden

Beachten Sie auch, dass ($) ist die Identitätsfunktion spezialisiert Typen funktionieren . Die Identitätsfunktion sieht wie folgt aus:

id :: a -> a
id x = x

Während ($) sieht wie folgt aus:

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

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

Uses of ($) kann in der Regel durch Zugabe von Klammern beseitigt werden (es sei denn, der Betreiber in einem Abschnitt verwendet wird). Z.B .: f $ g x wird f (g x).

Uses of (.) sind oft etwas schwieriger zu ersetzen; sie müssen in der Regel eine Lambda oder die Einführung eines expliziten Funktionsparameter. Zum Beispiel:

f = g . h

wird

f x = (g . h) x

wird

f x = g (h x)

Hope, das hilft!

($) ermöglicht Funktionen miteinander verkettet werden Klammern ohne Zugabe Auswertung zu steuern, um:

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

Prelude> head $ tail "asdf"
's'

Der compose Operator (.) erstellt eine neue Funktion, ohne die Argumente zu spezifizieren:

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, aber zeigt nicht wirklich die Bequemlichkeit Zusammensetzung zu verwenden. Hier ist eine andere Analogie:

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

Wenn wir dritte nur einmal verwenden, wir vermeiden können, es zu benennen, indem ein Lambda mit:

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

Schließlich Zusammensetzung läßt uns das Lambda vermeiden:

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

Die kurze und süße Version:

  • ($) ruft die Funktion, die sein linkes Argument auf dem Wert ist, der sein rechtes Argument ist.
  • (.) komponiert die Funktion, die auf der Funktion sein linkes Argument ist, das sein rechtes Argument ist.

Eine Anwendung, die nützlich ist und hatte mir einige Zeit von der sehr kurzen Beschreibung, um herauszufinden, bei lernen Sie eine Haskell : Da:

f $ x = f x

einklammern und die rechte Seite eines Ausdrucks eines Infixoperator wandelt es in eine Präfix-Funktion enthält, kann man schreiben ($ 3) (4+) analog (++", world") "hello".

Warum sollte das jemand tun? Eine Liste der Funktionen, zum Beispiel. Beide:

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

und

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

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

... oder Sie könnten die . und $ Konstruktionen unter Verwendung von Pipelining vermeiden:

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

Das ist, nachdem Sie in der Hilfefunktion hinzugefügt haben:

(|>) x y = y x

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

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

und

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

Denken Sie daran, :t verwenden zügig, und wickeln Sie Ihre Betreiber in ()!

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

  • verwenden nicht . wenn Sie den Parameter (rufen Sie die Funktion) übergeben möchten, und
  • nicht $ verwenden, wenn kein Parameter noch ist (komponiert eine Funktion)

Das ist

show $ head [1, 2]

aber nie:

show . head [1, 2]

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

Was ist der Unterschied zwischen dem Punkt (.) und das Dollarzeichen ($)?.Soweit ich weiß, handelt es sich bei beiden um syntaktischen Zucker, da keine Klammern verwendet werden müssen.

Sie sind nicht syntaktischer Zucker, weil keine Klammern verwendet werden müssen – es sind Funktionen – mit Infixen, daher können wir sie Operatoren nennen.

Komponieren, (.), und wann man es verwendet.

(.) ist die Compose-Funktion.Also

result = (f . g) x

ist dasselbe wie das Erstellen einer Funktion, die das Ergebnis ihres übergebenen Arguments übergibt g auf zu f.

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

Verwenden (.) wenn Sie nicht über die Argumente verfügen, die Sie an die Funktionen übergeben können, die Sie erstellen möchten.

Rechtsassoziativ anwenden, ($), und wann man es verwendet

($) ist eine rechtsassoziative Anwendungsfunktion mit niedriger Bindungspriorität.Es berechnet also zunächst lediglich die Dinge rechts davon.Daher,

result = f $ g x

ist verfahrensmäßig dasselbe (was wichtig ist, da Haskell träge ausgewertet wird und mit der Auswertung beginnt f Erste):

h = f
g_x = g x
result = h g_x

oder prägnanter:

result = f (g x)

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

Wir können dies sehen, indem wir die Quelle für jede Funktion lesen.

Lesen Sie die Quelle

Hier ist die Quelle 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 das Quelle 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) xs@,
-- or @'Data.List.zipWith' ('$') fs xs@.
{-# INLINE ($) #-}
($)                     :: (a -> b) -> a -> b
f $ x                   =  f x

Abschluss

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

Verwenden Sie application, wenn Sie alle Argumente für eine vollständige Auswertung angeben.

Für unser Beispiel wäre es also semantisch vorzuziehen, dies zu tun

f $ g x

wenn wir haben x (oder eher, g's Argumente) und tun:

f . g

wenn wir es nicht tun.

Ich denke, ein kurzes Beispiel, wo Sie . verwenden würden und nicht $ helfen, die Dinge klarstellen würde.

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

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

Beachten Sie, dass times6 eine Funktion, die von der Funktion Zusammensetzung erzeugt wird.

Alle anderen Antworten sind ziemlich gut. Aber es ist ein wichtiges Usability Detail darüber, wie ghc behandelt $, dass der ghc Typprüfer für instatiarion mit höheren Rang / quantifizierten Typen erlaubt. Wenn Sie auf die Art der $ id zum Beispiel suchen Sie finden es Gonna Take ist eine Funktion, deren Argument ist selbst eine polymorphe Funktion. Kleine Dinge wie, dass nicht die gleiche Flexibilität mit einem gleichwertigen Verstimmung Betreiber gegeben. (Das macht mich wirklich fragen, ob $! Die gleiche Behandlung verdient oder nicht)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top