www.jammni.de

Logo - Kleiner Drache
Login
Username:

Passwort:

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

Logo - DracheHaskell-Forum

WoLambda

Gepostet:
12.01.2012 21:53

Ausführungsreihenfolge bei Monaden  
Moin, moin!

Ich bin noch recht neu in Haskell und schlage mich gerade mit einem konzeptionellen Problem herum. Am Beispiel beschrieben, ist...
main = do
putStrLn \"Vorname: \"
vorname <- getLine
putStrLn \"Nachname: \"
nachname <- getLine
putStrLn (vorname ++ \" \" ++ nachname)
...identisch mit...
main = machs

machs =
(>>=) (putStrLn \"Vorname: \")
(\\ _ -> (>>=) getLine
(\\ vorname -> (>>=) (putStrLn \"Nachname: \")
(\\ _ -> (>>=) getLine
(\\ nachname -> putStrLn (vorname ++ \" \" ++ nachname))
)
)
)
...wobei ich nur jede Art von syntaktischem Zucker entfernt habe.

Mir geht es um folgendes Verständnisproblem: (>==) ist eine Funktion, die zwei Parameter hat, eine Aktion und eine Funktion. Die erste Aktion putStrLn \"Vorname: \" liefert ja keinen Wert an die durch (>==) aufgerufene Funktion, was wegen \\_ -> auch der Haskell-Compiler \"sieht\". Er könnte also wegen der Haskell-Lazyness durchaus zuerst die Funktion ausführen, bevor die Ausgabe erfolgt, da deren \"Wert\" für die Ausführung der Funktion nicht nötig ist.

Ich sehe nicht, wieso allein durch diesen Monaden-Operator (>==) im Fall \\ _ -> eine Ausführungsreihenfolge erzwungen wird - oder liegt das daran, dass bei Monaden Haskell wegen der Nebenwirkungen die Lazyness aufgibt?

...oder habe ich da irgend etwas übersehen????

PS: Habe Probleme die erzeugten Backslashes aus demText wegzubekommen
Zum Seitenanfang    
 
WoLambda

Gepostet:
13.01.2012 16:12

Ergänzung  
Vielleicht wird aus dem obigen Text mein Anliegen nicht so ganz klar, deshab noch eine kleine Ergänzung. Die definition von \"machs\" hat gekürzt folgende Form:

(>>=) (putstrLn \"Vorname: \") (\\ _ -> ...)

Da der zweite Parameter der Funktion (>>=), wegen des Dummy-Parameters im Lambda-Ausdruck, für seine Auswertung die vorherige Auswertung des ersten Parameters nicht benötigt, sehe ich nicht, wieso rein formal eine Ausführungsreihenfolge erzwungen wird. Es wäre etwas anderes, wenn dort ein echter Parameter stehen würde.

Woher weiss denn nun ein Lazyness berücksichtigender Haskell-Compiler, dass der erste Parameter zuerst ausgewertet werden muss, ohne dass er über die normalen Regeln der Auswertung hinausgehende Spezialinformationen braucht. Die Definition m a -> (a -> m b) -> m b, respective die \'abgekürzte\' von >>, die ja m a -> m b -> m b lautet, entspricht strukturell doch einer Funktionsdefinition

bla a b = b

bei der der Parameter a ja nicht ausgewertet werden muss und wegen der Lazyness auch nicht ausgewertet wird.

Nun ist ja eine Monade nichts Besonderes, sollte doch also seitens des Haskell-Compilers nicht anders behandelt werden, ausser es gäbe ein Bruch im puren System, der aber doch die Einführung der monadischen IO genau vermieden werden sollte.

Woher \'weiss\' der Haskell-Compiler also, dass er in (>>=) (putstrLn \"Vorname: \") (\\ _ -> ...) den ersten Parameter anfassen muss, während er das beim aufruf der oben definierten Funktion bla 41 42 nicht braucht?
Zum Seitenanfang    
 
Landei

Gepostet:
13.01.2012 16:37

   
Du vergisst, dass bei (>>) das Ergebnis der ersten Operation nicht einfach ignoriert werden kann, nur weil man nicht auf dessen Wert (innerhalb der Monade) schaut. Nehmen wir ein einfacheres Beispiel, die List-Monade:


[] >> [1,2,3]
-- []

\"bla\" >> [1,2,3]
-- [1,2,3,1,2,3,1,2,3]

\"foo\" >> [1,2,3]
-- [1,2,3,1,2,3,1,2,3]



Wie man sieht, wird der Wert des ersten Arguments tatsächlich ignoriert: Welche Buchstaben in der Liste stehen, ist völlig Wumpe. Trotzdem muss die \"Struktur\" der übergebenen Monade (hier die Länge der Liste) bekannt sein, also muss das erste Argument auch ausgewertet werden.

Bei putStrLn kann zwar (außer einem Fehler) nur IO () herauskommen, aber der Compiler kann nicht wissen, dass der Typ IO () nur von einem einzigen Wert bewohnt wird, und er hat keine Ahnung, wie man diesen Wert erzeugen könnte: Er hantiert ganz abstrakt mit Monaden als \"Black Box\" und hat nur Zugriff auf die dort definierten Funktionen, aber keinen Einblick in deren interne Struktur. Da aber die Struktur der übergebenen Monade - wie oben gezeigt - sehr wohl Einfluss auf die Berechnung des Gesamtergebnisses hat, bleibt dem Compiler nichts anderes übrig, als das erste Argument auch tatsächlich auszuwerten, und zwar bevor er sich dem zweiten widmet.
Zum Seitenanfang    
 
WoLambda

Gepostet:
14.01.2012 14:04

Danke für die Erklärungen  
Vielen Dank für die Antwort. Ich werde mal ganz in Ruhe darumer nachdenken. Ich habe die Frage auch im Ruby-Forum im \\\"off-topic\\\"-Bereich gepostet und durch Vermittlung eines anderen Moderators dort eine Antwort erhalten: [url]http://forum.ruby-portal.de/viewtopic.php?f=12&t=12938&start=1[/url]

Diese Frage ist zwar für mich nicht für das Schreiben von Programmen relevant, aber es interessiert mich halt, das detailliert nachvollziehen zu können.
Zum Seitenanfang    
 
Landei

Gepostet:
14.01.2012 21:23

   
So ungefähr decken sich unsere Erklärungen, meine ist etwas abstrakter, seine etwas technischer. Was ich noch nicht erwähnt hatte ist, dass es auch andere Möglichkeiten gibt, das Problem zu lösen. Das zu Haskell sehr ähnliche Clean unterstützt z.B. Uniqueness Types (siehe http://en.wikipedia.org/wiki/Uniqueness_type ), also Typen, auf deren Werte zu jedem Zeitpunkt höchstens eine Referenz existieren darf.
Zum Seitenanfang    
 
WoLambda

Gepostet:
15.01.2012 01:05

Der Nebel lichtet sich...  
Ich muss sagen, dass sich die Beschäftigung mit Haskell schon deshalb lohnt, weil das alles sehr interessant ist.
Zum Seitenanfang