Difference between revisions of "De/Flussrichtung"
(first raw version) |
(Markup) |
||
Line 1: | Line 1: | ||
− | Wenn man sich mal genauer umschaut, gibt es in Haskell beide Varianten gleich |
+ | Wenn man sich mal genauer umschaut, gibt es in Haskell beide Varianten gleich häufig. |
Wir haben die Schreibweisen: |
Wir haben die Schreibweisen: |
||
− | links nach rechts: |
||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
− | rechts |
+ | links nach rechts: |
+ | {| |
||
− | Funktionsanwendung f x |
||
⚫ | |||
− | f $ x |
||
+ | |- |
||
− | Verkettung g . f |
||
⚫ | |||
⚫ | |||
+ | |- |
||
⚫ | |||
⚫ | |||
+ | |- |
||
⚫ | |||
+ | |} |
||
+ | rechts nach links: |
||
⚫ | |||
+ | {| |
||
⚫ | |||
+ | | Funktionsanwendung || <hask> f x </hask>, <hask> f $ x </hask> |
||
⚫ | |||
+ | |- |
||
⚫ | |||
+ | | Verkettung || <hask> g . f </hask> |
||
⚫ | |||
+ | |- |
||
⚫ | |||
+ | |- |
||
⚫ | |||
+ | |} |
||
+ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
Auch |
Auch |
||
− | do f -> x; g x |
+ | <hask> do f -> x; g x </hask> |
− | + | wäre schon viel näher an der darunterliegenden Implementierung |
|
− | f >>= |
+ | <hask> f >>= \x -> g x </hask> |
− | Allerdings sehe ich noch zwei |
+ | Allerdings sehe ich noch zwei Unschönheiten/Gewöhnungsbedürftigkeiten: |
− | Eines tritt beim Lesen von links-nach-rechts- |
+ | Eines tritt beim Lesen von links-nach-rechts-Ausdrücken auf: Man sieht |
− | bei der Verwendung von Funktionen |
+ | bei der Verwendung von Funktionen höherer Ordnung nicht sofort, wo die |
− | Argumente eines Funktionsaufrufes |
+ | Argumente eines Funktionsaufrufes aufhören. Mein Lieblingsbeispiel - der |
− | Differentialoperator |
+ | Differentialoperator <hask>derive</hask>: |
− | + | <hask> derive :: (a -> a) -> (a -> a) </hask> |
|
− | Wenn man den Ausdruck |
+ | Wenn man den Ausdruck <hask> x f derive </hask> nur bis <hask> f </hask> liest, denkt man, es |
− | handelt sich um die Anwendung von f auf x und danach kommt noch irgendwas. |
+ | handelt sich um die Anwendung von <hask> f </hask> auf <hask> x </hask> und danach kommt noch irgendwas. |
− | Aber nein, durch |
+ | Aber nein, durch <hask> derive </hask> wird alles umgekrempelt. |
− | Ausdruck erst bis zum |
+ | Man muss also einen Ausdruck erst bis zum nächsten Absatz |
− | Infixoperator) lesen, |
+ | (schließende Klammer, Infixoperator) lesen, |
− | eigentlich handelt. |
+ | bis man weiß, um welchen Funktionsaufruf es sich eigentlich handelt. |
− | Die zweite Sache ist die Verbindung von Typsignatur und |
+ | Die zweite Sache ist die Verbindung von Typsignatur und Funktionsanwendung. |
− | + | Wir schreiben |
|
+ | <haskell> |
||
derive :: (a -> a) -> (a -> a) |
derive :: (a -> a) -> (a -> a) |
||
derive f :: a -> a |
derive f :: a -> a |
||
derive f x :: a |
derive f x :: a |
||
+ | </haskell> |
||
− | Wir |
+ | Wir können gewissermaßen die Argumente von der Typseite auf die |
Werteseite umschichten. Die Argumentreihenfolge ist daher in |
Werteseite umschichten. Die Argumentreihenfolge ist daher in |
||
Typsignatur und Funktionsanwendung gleich. Bei der konsequenten |
Typsignatur und Funktionsanwendung gleich. Bei der konsequenten |
||
links-nach-rechts-Notation ist das nicht mehr der Fall: |
links-nach-rechts-Notation ist das nicht mehr der Fall: |
||
+ | <haskell> |
||
derive :: (a -> a) -> (a -> a) |
derive :: (a -> a) -> (a -> a) |
||
f derive :: a -> a |
f derive :: a -> a |
||
x f derive :: a |
x f derive :: a |
||
+ | </haskell> |
||
− | Die Notation hat |
+ | Die Notation hat natürlich den unbestreitbaren Vorteil, dass man sich |
− | + | <hask>::</hask> wie ein Gleichheitszeichen vorstellen kann, wo man auf beiden Seiten |
|
der Gleichung die Ausdruecke immer von links manipuliert. |
der Gleichung die Ausdruecke immer von links manipuliert. |
||
+ | |||
+ | [[Category:Syntax]] |
Revision as of 14:37, 19 March 2007
Wenn man sich mal genauer umschaut, gibt es in Haskell beide Varianten gleich häufig. Wir haben die Schreibweisen:
links nach rechts:
Funktionsdefinition | f x = x*x (links Eingabe, rechts Ausgabe)
|
Lambda | \ x -> x*x
|
do-notation | do f; g
|
monadische Verkettung | f >>= g
|
rechts nach links:
Funktionsanwendung | f x , f $ x
|
Verkettung | g . f
|
Ergebnisse von Monaden | do x <- f
|
monadische Verkettung | g =<< f
|
Lambda-Ausdrücke sähen viel natürlicher aus, wenn die Verkettung von links nach rechts gehen würde, also statt
transform3 . (\x -> transform2 x x) . transform1
besser
transform1 . (\x -> x x transform2) . transform3
Auch
do f -> x; g x
wäre schon viel näher an der darunterliegenden Implementierung
f >>= \x -> g x
Allerdings sehe ich noch zwei Unschönheiten/Gewöhnungsbedürftigkeiten:
Eines tritt beim Lesen von links-nach-rechts-Ausdrücken auf: Man sieht
bei der Verwendung von Funktionen höherer Ordnung nicht sofort, wo die
Argumente eines Funktionsaufrufes aufhören. Mein Lieblingsbeispiel - der
Differentialoperator derive
:
derive :: (a -> a) -> (a -> a)
Wenn man den Ausdruck x f derive
nur bis f
liest, denkt man, es
handelt sich um die Anwendung von f
auf x
und danach kommt noch irgendwas.
Aber nein, durch derive
wird alles umgekrempelt.
Man muss also einen Ausdruck erst bis zum nächsten Absatz
(schließende Klammer, Infixoperator) lesen,
bis man weiß, um welchen Funktionsaufruf es sich eigentlich handelt.
Die zweite Sache ist die Verbindung von Typsignatur und Funktionsanwendung. Wir schreiben
derive :: (a -> a) -> (a -> a)
derive f :: a -> a
derive f x :: a
Wir können gewissermaßen die Argumente von der Typseite auf die
Werteseite umschichten. Die Argumentreihenfolge ist daher in Typsignatur und Funktionsanwendung gleich. Bei der konsequenten links-nach-rechts-Notation ist das nicht mehr der Fall:
derive :: (a -> a) -> (a -> a)
f derive :: a -> a
x f derive :: a
Die Notation hat natürlich den unbestreitbaren Vorteil, dass man sich
::
wie ein Gleichheitszeichen vorstellen kann, wo man auf beiden Seiten
der Gleichung die Ausdruecke immer von links manipuliert.