www.jammni.de

Logo - Kleiner Drache
Login
Username:

Passwort:

Daten merken
Auto-Login
Registrieren
 
Online
niemand
 
Forumsuche
Suche nach:

Logo - DracheHaskell-Forum

anduril

Gepostet:
11.02.2006 13:34

Warum funktioniert Currying?  
Hi,
ich hab ein Problem mit der Implementierung von Currying:

curry :: ((a,b)->c)->a->b->c
curry f = g
where g x y=f(x,y)

Natürlich weiß ich was Currying macht und wofür es gut ist, nur wieso es das macht ist mir nicht klar. Wenn ich eine Funktion (a,b)->c in f speichere, dann wird
a,b in x gespeichert und c in y. Als Ergebnis krieg ich dann f((a,b),c) aber wie komm ich von da auf a->(b->c)??
Zum Seitenanfang    
 
Jacke

Gepostet:
12.02.2006 15:30

   
hi bin grade erst aus dem wochenende zurrück ic antworte dir aber heute abend...
Zum Seitenanfang    
 
Jacke

Gepostet:
12.02.2006 19:59

   
Also hier mal ne Beispiel von ner anderen website:

"Currying" (nach Haskell Curry)

* Funktionen mit n>1 Parametern werden in Haskell als solche mit einem Parameter interpretiert, die einen Ausdruck auf den restlichen n-1 Parametern zurückliefern (Implizites "Currying").

* "curried function":

add :: Integer->Integer->Integer
add a b = a + b

* Die Anwendung der Funktion ist links-assoziativ: add a b <=> (add a) b

* Der Ausdruck wird zu der Funktion "addiere a" mit dem Parameter b umgeformt.

* Dies entspricht der äquivalenten Typsignatur Integer->(Integer->Integer), also einem Integer als Parameter und einer Funktion mit einem Integer-Parameter als Rückgabewert.

* "Uncurried functions" sind entsprechend Funktionen mit genau einem Parameter (auch Tupel)

Partielle Anwendung

* Mit Hilfe von "curried functions" können spezialisierte Adapter-Ausdrücke definiert werden, die diese anwenden.

* Beispiel

mult :: Float->(Float->Float)
mult a b = a * b

Durch partielle Anwendung der "curried function" mult kann die Verdopplungs-Funktion als spezielle Multiplikation implementiert werden:


doppel = mult 2 -- "Explizites Currying"

doppel 3 -- wird zu 6 ausgewertet




so und jetzt zur erklärung die funktion curry kriegt als eingabe typ:
a,b in x gespeichert und c in y. Als Ergebnis krieg ich dann f((a,b),c)

und als rückgabe hat mal dieselbe funktion mit der äquivalenten Typsignatur a->(b->c), also einem a als Parameter und einer Funktion mit einem c-Parameter als Rückgabewert.
Zum Seitenanfang    
 
anduril

Gepostet:
12.02.2006 20:40

   
Hi,
schonmal danke für die Antwort. Das Beispiel hatte ich auch schon gefunden Smilie
Mein Problem ist, das ich nicht verstehe das f((a,b),c) die Typsignatur a->b->c hat. Für mich sieht das so aus, als würde ich eine Funktion f::(a,b)->c zurückgeben die ein Tupel als Eingabe bekommt und das Ganze als c ausgibt. Das ursprüngliche Tupel (a,b)=x und c=y wird durch (x,y) übergeben. Das wiederum würde aber heißen, das das a in f das ursprüngliche Tupel (a,b) ist und b das nicht berechnete Ergebnis. Allerdings muss ich doch irgendwie eine anonyme Lambdafunktion zurückgeben die nur ein Argument a (das auch übergeben wird) erwartet und als Rückgabe eine Funktion b->c damit Currying so funktioniert... Wenn du das entwirren kannst wär ich dir sehr dankbar. Vielleicht kannst du ja mal genau die einzelnen Schritte aufschreiben die beim Currying vom System gemacht werden

Zum Seitenanfang    
 
Jacke

Gepostet:
12.02.2006 21:40

   
ja ich seh schon alles total konfus...ich glaub ich erklärs mal ganz ganz ausführlich

also das wäre eine curried version von mul...das heißt die argumente können auch erstmal irgendwo ausgerechnet werden..und und und
mul::Int->Int->Int
mul x y =x*y

eine uncurriedversion von mul also mit gebündelten argumenten zu einen paar wäre dann
mul2::(Int,Int)->Int
mul2 (x,y) =x*y

warum benutzt man normalerweise die curriedform?:
weil man zum beipiel mul 2 schreiben kann und dann keinen fehler bekommt sondern ne funktion...

so und die funktion
curry :: ((a,b)->c)->(a->b->c)
curry g x y= g (x,y)

macht dann aus mul2 wieder mul1

curry mul ...
wie gesagt nicht verwirren lassen...jetzt weißt du ja wofürs gut is...es hebt einfach nur die klammerung auf


mul :: Integer->Integer->Integer
mul a b = a + b

--ist dasselbe wie dein curry
curry :: ((a,b)->c)->a->(b->c)
curry g x y=g(x,y)

mul2::(Int,Int)->Int
mul2 (x,y) =x*y


Aufruf :

c:\curry mul2 1 2
2
c:\


es gibt auch ne funktion uncurry die sieht dann genau andersrum aus und macht aus mul1 dann mul2


uncurry :: (a->b->c)->((a,b)->c)
uncurry f(x,y) =f x y
Zum Seitenanfang    
 
anduril

Gepostet:
12.02.2006 22:16

   
Ich glaube langsam geht mir ein Licht auf...

Ich nummeriere in der Typbezeichnung von curry mal die Argumente durch:

curry :: ((a1,b2)->c3)->a4->b5->c6
curry f = g
where g x y=f(x,y)

f ist also (a1,b2)->c3; x ist a4, y ist b5 und das Ergebnis von f ist c6. Was mich nur noch wundert ist, dass das Pattern Matching funktioniert, denn die zweite Zeile matcht doch nur auf eine Funktion (a1,b2)->c3, übergeben wird aber doch (a1,b2)->c3->a4->b5
Zum Seitenanfang    
 
Jacke

Gepostet:
12.02.2006 22:32

   
das ist die eingabe (zum beispiel mul2)
(a1,b2)->c3

und das ist die rückgabe (das wäre dann mul)

a4->b5->c6

du haust ne ganz fuktion in das curry rein und kriegst auch die ganze funktion wieder raus...(natürlich rechnet haskell das dann gleich aus)

gruß jacke :-)
Zum Seitenanfang    
 
anduril

Gepostet:
12.02.2006 23:26

   
ok es wird immer heller... Smilie
da haskell bei den funktionsanwendungen linksassoziativ arbeitet, wird
((curry mul2) 1) 2
intern so geklammert, d.h. curry gibt eine lambdafunktion
\a4 b5->c6
zurück (x=a4; y=b5; x*y=c6) die auf die Eingabe von zwei Werten wartet "x,y", anschließend wieder in curry reinspringt und diese an die originale Funtion f weitergibt die das Ergebnis c6 dann berechnet. Jetzt richtig???
Zum Seitenanfang    
 
Jacke

Gepostet:
13.02.2006 08:38

   
ja genau in a1=x a2=y c3=x*y
und dann die orginalfunktion auf die hat in a4=x in a5=y c6=x*y
das ergebnis ist in c6
Zum Seitenanfang    
 
anduril

Gepostet:
13.02.2006 14:27

   
vielen dank Smilie
Zum Seitenanfang