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.
Eine Anwendung, die nützlich ist und die mir einige Zeit gekostet hat, um sie aus der sehr kurzen Beschreibung bei Learn You a Haskell zu verstehen: Da
f $ x = f x
und wenn man den rechten Teil eines Ausdrucks, der einen Infix-Operator enthält, in Klammern setzt, wird er zu einer Präfixfunktion, kann man ($ 3) (4 +)
schreiben, analog zu (++ ", world") "hello"
.
Warum sollte das jemand tun? Zum Beispiel für Listen von Funktionen. Beides:
map (++ ", world") ["hello", "goodbye"]
map ($ 3) [(4 +), (3 *)]
sind kürzer als
map (\x -> x ++ ", world") ["hello", "goodbye"]
map (\f -> f 3) [(4 +), (3 *)]
Offensichtlich wären die letzteren Varianten für die meisten Menschen lesbarer.
Übrigens würde ich davon abraten, $3
ohne Leerzeichen zu verwenden. Wenn Template Haskell aktiviert ist, wird dies als Splice analysiert, während $ 3
immer das bedeutet, was du gesagt hast. Im Allgemeinen scheint es in Haskell einen Trend zu geben, dass bestimmte Operatoren durch das Bestehen darauf, dass um sie herum Leerzeichen stehen, "gestohlen" werden sollen.
Ich brauchte eine Weile, um herauszufinden, wie die Klammern funktionieren: en.wikibooks.org/wiki/Haskell/…
Haskell: Unterschied zwischen
.
(Punkt) und$
(Dollarzeichen)Was ist der Unterschied zwischen dem Punkt
(.)
und dem Dollarzeichen($)
? So wie ich es verstehe, sind sie nur Zucker für die Syntax, um keine Klammern verwenden zu müssen.
Sie sind nicht nur Zucker für die Syntax, um keine Klammern verwenden zu müssen - sie sind Funktionen, - infix, daher können wir sie Operatoren nennen.
(.)
und wann es zu verwenden ist.(.)
ist die Kompositions-Funktion. Also
result = (f . g) x
ist dasselbe wie eine Funktion zu erstellen, die das Ergebnis ihres Arguments, das an g
übergeben wurde, an f
weitergibt.
h = \x -> f (g x)
result = h x
Verwende (.)
, wenn du die Argumente nicht verfügbar hast, um sie an die Funktionen zu übergeben, die du komponieren möchtest.
($)
und wann es zu verwenden ist($)
ist eine rechts-assoziative Anwendungs-Funktion mit niedriger Bindungspräzedenz. Es berechnet also einfach die Dinge rechts von ihm zuerst. Daher ist
result = f $ g x
prozedural dasselbe wie dies (was wichtig ist, da Haskell faul ausgewertet wird, beginnt es zuerst f
auszuwerten):
h = f
g_x = g x
result = h g_x
oder kürzer ausgedrückt:
result = f (g x)
Verwende ($)
, wenn du alle Variablen hast, die du auswerten möchtest, bevor du die vorherige Funktion auf das Ergebnis anwendest.
Wir können dies erkennen, indem wir den Quellcode jeder Funktion lesen.
Hier ist der Quellcode für (.)
:
-- | Funktionskomposition.
{-# INLINE (.) #-}
-- Stelle sicher, dass es nur ZWEI Argumente links hat, sodass es eingebaut wird,
-- wenn es auf zwei Funktionen angewendet wird, selbst wenn es kein Endargument gibt
(.) :: (b -> c) -> (a -> b) -> a -> c
(.) f g = \x -> f (g x)
Und hier ist der Quellcode für ($)
:
-- | Anwendungsoperator. Dieser Operator ist überflüssig, da
-- normale Anwendung @(f x)@ dasselbe bedeutet wie @(f '$' x)@. Jedoch hat '$'
-- eine niedrige, rechts-assoziative Bindungspräzedenz, sodass es manchmal Klammern weglassen ermöglicht; zum Beispiel:
--
-- > f $ g $ h x = f (g (h x))
--
-- Er ist auch nützlich in Situationen höherer Ordnung, wie bei @'map' ('$' 0) xs@,
-- oder @'Data.List.zipWith' ('$') fs xs@.
{-# INLINE ($) #-}
($) :: (a -> b) -> a -> b
f $ x = f x
Verwende Komposition, wenn du die Funktion nicht sofort auswerten musst. Vielleicht möchtest du die aus der Komposition resultierende Funktion an eine andere Funktion weitergeben.
Verwende Anwendung, wenn du alle Argumente für eine vollständige Auswertung bereitstellst.
Also wäre es semantisch bevorzugt, in unserem Beispiel
f $ g x
zu machen, wenn wir x
haben (bzw. die Argumente von g
), und
f . g
wenn wir es nicht haben.
Eine Sache, die hier zu beachten ist, besteht darin, dass der Operator $
in Haskell tatsächlich eher wie <|
in F# als wie |>
funktioniert. Normalerweise würde man in Haskell die obige Funktion so schreiben: third xs = head $ tail $ tail $ xs
oder vielleicht sogar wie third = head . tail . tail
, was in F#-ähnlicher Syntax etwa so aussehen würde: let third = List.head << List.tail << List.tail
Ein großartiger Weg, um mehr über irgendetwas (jede Funktion) zu erfahren, besteht darin, sich daran zu erinnern, dass alles eine Funktion ist! Dieses allgemeine Mantra hilft, aber in spezifischen Fällen wie Operatoren hilft es, sich diesen kleinen Trick zu merken:
:t (.)
(.) :: (b -> c) -> (a -> b) -> a -> c
und
:t ($)
($) :: (a -> b) -> a -> b
Vergiss nicht, :t
großzügig zu verwenden und deine Operatoren in ()
zu verpacken!
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.