2013-04-03 6 views
8

Ich weiß

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

Intuitiv scheint es mir, wie, sagen 1. $ verzögert die Auswertung der Funktion auf der linken 2. wertet was zu seiner rechten 3. führt das Ergebnis ihrer links von rechts.

Und es macht Sinn für mich, wenn,

ghci> length $ [1..5] 
5 
ghci> ($) length [1..5] 
5 

Was ich nicht verstehe ist, warum,

ghci> ($ [1..5]) length 
5 

vom Typ von $ zu urteilen, ist nicht, dass seine (erste) Argument sollte eine Funktion sein?

+13

Hier geht es nicht um '($)', sondern um Operatorabschnitte. – phg

+9

'$' * verzögert die Auswertung der Funktion nicht. Sie können es mit '$!' Verwechseln, was eine Teilbewertung des Arguments nach rechts bewirkt, bevor es der Funktion zu seiner Linken zugeführt wird. – dave4420

+0

Dies ist "Abschnitt" -Syntax bei der Arbeit. http://www.haskell.org/onlinereport/haskell2010/haskellch3.html#x8-300003.5 –

Antwort

15

Das hat mit dem Parsen zu tun. In Haskell können Sie (op arg) schreiben, wobei op ein Infix-Operator ist. Dies ist nicht dasselbe wie ((op) arg). Und Sie können auch (arg op) schreiben! Zum Beispiel:

GHCi, version 7.0.3: http://www.haskell.org/ghc/ :? for help 
Prelude> :t (+ 4) 
(+ 4) :: Num a => a -> a 
Prelude> :t (4 +) 
(4 +) :: Num a => a -> a 

Das heißt, (+ 4) ist die Funktion \x -> x + 4 und (4 +) ist die Funktion \y -> 4 + y. Im Fall von Addition sind das gleiche Funktionen, aber das ist im Moment nicht wirklich wichtig.

lassen Sie uns nun den gleichen Trick auf $ versuchen:

Prelude> :t ($ [1,2,3,4]) 
($ [1,2,3,4]) :: Num t => ([t] -> b) -> b 

Jetzt Überraschung so weit, wir haben \f -> f $ [1,2,3,4]. Wir können auch schreiben

Prelude> :t (length $) 
(length $) :: [a] -> Int 

die Funktion \l -> length $ l zu erhalten. Aber wie wäre es damit:

Prelude> :t ($ length) 
($ length) :: (([a] -> Int) -> b) -> b 

Das ist seltsam, aber es macht Sinn! Wir haben \f -> f $ length, d.h., eine funktionale, die eine Funktion f des Typs ([a] -> Int) -> b) erwartet, die auf length angewendet wird. Es gibt eine vierte Möglichkeit:

Prelude> :t ([1,2,3,4] $) 

<interactive>:1:2: 
    Couldn't match expected type `a0 -> b0' with actual type `[t0]' 
    In the first argument of `($)', namely `[1, 2, 3, 4]' 
    In the expression: ([1, 2, 3, 4] $) 

Alles ist, wie es sein sollte, weil [1,2,3,4] keine Funktion ist. Was ist, wenn wir $ in Klammern schreiben? Dann seine besondere Bedeutung als Infixoperator verschwindet:

Prelude> :t (($) length) 
(($) length) :: [a] -> Int 

Prelude> :t (($) [1,2,3,4]) 
<interactive>:1:6: 
    Couldn't match expected type `a0 -> b0' with actual type `[t0]' 
    In the first argument of `($)', namely `[1, 2, 3, 4]' 
    In the expression: (($) [1, 2, 3, 4]) 

Prelude> :t (length ($)) 
<interactive>:1:9: 
    Couldn't match expected type `[a0]' 
       with actual type `(a1 -> b0) -> a1 -> b0' 
    In the first argument of `length', namely `($)' 
    In the expression: (length ($)) 

Prelude> :t ([1,2,3,4] ($)) 
<interactive>:1:2: 
    The function `[1, 2, 3, 4]' is applied to one argument, 
    but its type `[t0]' has none 
    In the expression: ([1, 2, 3, 4] ($)) 

Also, Ihre Frage zu beantworten: $ [1,2,3,4] analysiert wird als \f -> f $ [1,2,3,4] so macht es durchaus Sinn, es zu length anzuwenden. ($) [1, 2, 3, 4] macht jedoch keinen Sinn, da ($) nicht als Infix-Operator betrachtet wird.

Übrigens, $ tut "nichts", sozusagen. Es wird hauptsächlich für lesbarere Eingaben verwendet, da es eine niedrige Priorität hat und wir daher f $ g $ h $ x anstelle von f (g (h x)) schreiben können.

+1

'-' könnte eine schlechte Wahl für das Beispiel gewesen sein, da es die einzige Ausnahme ist, in der' (op arg) '* keine * Funktion darstellt. –

+1

Auch haben '((-) 4)' und '(4 -)' die gleiche Funktion, '(\ x -> 4 - x)'. –

+0

Bedeutet es, weil (-) links zugeordnet ist, sowohl ((-) 4) als auch (4 -) bedeutet (\ x -> 4 - x), während ($) rechtsverbunden ist, sowohl ($ func) als auch ($ arg) bedeutet (\ x -> bar $ a) wobei a func oder arg bedeutet? – Znatz

6

($ [1..5]) ist ein Abschnitt. Das ist ein teilweise angewandter Operator. Es ist eine Kurzschrift für (\f -> f $ [1..5]).

In den Abschnitten können Sie einem binären Operator ein Argument übergeben und eine Funktion erstellen - eine Funktion, die auf das verbleibende Argument wartet.

Werfen Sie einen Blick auf http://www.haskell.org/haskellwiki/Section_of_an_infix_operator

10

Ihre Frage ist wirklich, was Operator Abschnitte genannt wird. Mit jedem Operator in Haskell (ich werde + als Beispiel verwenden) können Sie etwas wie (+ arg) oder (arg +) schreiben. Dies sind nur Kurzschriftsyntax für die anonymen Funktionen (\x -> x + arg) bzw. (\x -> arg + x).

So ist die Syntax ($ [1..5]) bedeutet nur (\x -> x $ [1..5]) welche die gleiche ist wie (\x -> x [1..5]) (dh. Eine Funktion, die [1..5] an die Funktion als Argument übergeben gibt).

+0

Dieses (\ x -> x $ [1..5]) räumt wirklich meine Verwirrung auf! – Znatz