2015-05-14 11 views
10

Flipping Sagen definiere ich diese Funktion:Haskell: ein curried Dollar Operator

f = ($ 5) 

Dann kann ich es anwenden:

> f (\x -> x^2) 
25 

Seine Art ist:

:t f 
f :: (Integer -> b) -> b 

Das macht Sinn Er erhält eine Funktion als Argument und gibt diese Funktion auf die Integer5 zurück.

Nun definiere ich diese Funktion:

g = flip f 

Ich würde erwarten, dass dieses Gefühl nicht machen, weil f eine Funktion von einem einzigen Argumente ist.

Aber seine Art Prüfung:

:t g 
g :: b -> (Integer -> b -> c) -> c 

So, jetzt g ist eine Funktion von zwei Argumenten!

Anwendung auf einige Werte:

> g [2, 4, 6] (\x y -> x:y) 
[5,2,4,6] 

Was ist hier los? Was bedeutet flip ($ 5) wirklich?

Antwort

7

Folgen Sie den Typen:

($ 5) :: (Int -> a) -> a 
flip :: (x -> y -> z) -> y -> x -> z 

Aber da -> Recht assoziativ ist, die Art x -> y -> z entspricht x -> (y -> z), so

flip :: (x   -> (y -> z)) -> y -> x -> z 
($ 5) :: (Int -> a) -> a 

So x ~ (Int -> a) und (y -> z) ~ a, so ersetzt zurück in:

($ 5) :: (Int -> (y -> z)) -> (y -> z) 

und vereinfachte

($ 5) :: (Int -> y -> z) -> y -> z 

So

flip ($ 5) :: y -> (Int -> y -> z) -> z 

die für den Typ Sie sehen gleichwertig ist (obwohl ich Int statt Integer verwendet Typisierung zu speichern).

Was dies sagt, ist, dass die Art der ($ 5) spezialisiert wird, wenn zu flip geleitet, so dass sie eine Funktion von zwei Argumenten übernehmen. Es ist absolut zulässig, etwas wie ($ 5) const zu haben, wobei const :: a -> b -> a und ($ 5) const :: b -> Int. Alle ($ 5) tun ist 5 als ein Argument an eine Funktion der Anwendung, die nicht unbedingt das Argument für eine Funktion. Dies ist ein Beispiel für eine partielle Anwendung, bei der nicht alle Argumente einer Funktion übergeben werden. Deshalb können Sie Dinge wie map (subtract 1) [1, 2, 3] tun.

Ein Beispiel, wie flip ($ 5) zu verwenden ist:

> flip ($ 5) 1 (**) 
25.0 
> flip ($ 5) 1 (-) 
4.0 
> let f x y = (x, y) 
> flip ($ 5) 1 f 
(5, 1) 
+0

Danke. Sie haben einen Fehler obwohl. Ich werde dir nicht sagen wo :-) – AmirW

1

die Funktion flip die Reihenfolge der Argumente kippt, so dass alle von ihnen sind gleich:

f (\x y -> x:y) [2, 4, 6] 

[5,2 , 4,6]

flip f [2, 4, 6] (\x y -> x:y) 

[5,2,4,6]

g [2, 4, 6] (\x y -> x:y) 

[5,2,4,6]

4

Die Verwirrung entsteht aus dem losen Konzept der „Anzahl der Argumente "für polymorphe Funktionen. Zum Beispiel ist es verlockend zu sagen, dass

hat ein Argument (eine Funktion). Noch eine genauere Aussage wäre, dass f eine Funktion mit mindestens ein Argument ist. Dies liegt daran, dass die Typvariable b durch Polymorphie mit jedem Typ ersetzt werden kann, was z.

f :: (Integer -> String) -> String 
f :: (Integer -> Double) -> Double 
... 

die in der Tat sind Funktionen mit einem Argument, sondern auch auf z.B.

f :: (Integer -> (String -> Double)) -> (String -> Double) 

wo bString -> Double mit einem funktionellen Typ ersetzt wurde. Diese Ersetzung bewirkt, dass ein zweites Argument scheinbar magisch erscheint: f kann ein erstes Argument (eine binäre Funktion Integer -> String -> Double) und dann ein zweites Argument (ein String) annehmen, bevor ein Double zurückgegeben wird.

Beachten Sie, dass dieses Phänomen immer dann auftritt, wenn ein polymorpher Typ mit ... -> b für eine Typvariable b endet.

Lassen Sie mich mit einer Kleinigkeit abschließen: Wie "viele" Argumente hat die Identitätsfunktion id? Nun, intuitiv würde ich sagen ein, aber lassen Sie mich prüfen ...

> id (+) 3 4 
7 
> id id id id id (+) 3 4 
7 

... und vielleicht viele ist eine bessere Antwort.