[Inhalt]...[Nicht-strikte Auswertung]
Das Informatik-Seminar der Fachhochschule Wedel im Sommersemester 2002 befasst sich unter anderem mit dem Thema "Funktionale Programmierung in Haskell" (betreut von Prof. Dr. Uwe Schmidt). Diese Ausarbeitung beschreibt die sogenannte "Lazy evaluation", sowie deren Vor- und Nachteile gegenüber "Call-by-value" und "Call-by-reference".
Code-Beispiel in Haskell [Quelldatei]
-- Beispiel fuer Funktion
-- 2. Beispiel fuer Funktion
module HaskFuncs where
Das obige Code-Beispiel stellt ein Haskell-Modul
mit Namen "HaskFuncs" dar. Es kann beispielsweise mit dem
HUGS98-Compiler aus einer Ascii-Datei geladen werden. Innerhalb des Moduls
werden zwei Funktionen deklariert, "mult" und
"mult2". Sie stehen nach Laden des
Moduls zur Verfügung und können an der Kommando-Zeile ausgeführt werden.
mult :: Float -> Float -> Float
mult a b = a * b
mult2 :: Float -> (Float -> Float)
mult2 a b = a * b
Die jeweils erste Zeile stellt die Deklaration der Typsignatur dar, und damit eine explizite Typbindung für die Funktion. "A Gentle Introduction to Haskell" empfiehlt die Verwendung von Typsignaturen, weil sie die Lesbarkeit des Codes erhöhen, und die Fehlererkennung vereinfachen. Der Doppelpunkt steht für "hat den Typ", während "->" als Zuordnungs- oder Funktionspfeil bezeichnet wird. Beide Funktionen sind Ausdrücke vom Typ Float und akzeptieren als Parameter genau zwei Float-Ausdrücke. Keine der Funktionen darf mit anderen Parametern als genau zwei Float-Ausdrücken aufgerufen werden, andernfalls wird zur Compile-Zeit ein Fehler generiert. Die zweite Zeile stellt die Gleichung und damit den eigentlichen Funktionsausdruck dar. Im Beispiel werden hier jeweils die beiden formellen Parameter der Funktion multipliziert. Bei erfolgreicher Typprüfung wird die Funktion zum Wert ihrer Gleichung ausgewertet. Schlägt die Typprüfung fehl, meldet der Compiler einen Fehler.
Funktionsaufruf (HUGS98)
HaskFuncs>mult 3 2
6.0
HaskFuncs>mult2 (-1) 2
-2.0
HaskFuncs>
Ausgabe des HUGS98 bei fehlgeschlagener Typprüfung
HaskFuncs>
HaskFuncs>mult 'a' 2
ERROR - Type error in application
*** Expression : mult 'a' 2
*** Term : 'a'
*** Type : Char
*** Does not match : Float
Durch Haskells statisches Typsystem wird der Fehler im Funktionsaufruf zur Compilezeit erkannt.
Der Compiler meldet einen Typfehler in der Anwendung. Der erste Parameter mit dem Wert 'a'
wird geprüft, und ein "Missmatch" zwischen den Typen
Char und Float wird festgestellt. Für die Übergabe von komplexen Ausdrücken als
Parameter ist die Klammerung Pflicht, da sonst Parserfehler entstehen. Beispielsweise
führt der Aufruf "mult -1 1
" zu einem Compiler-Fehler, weil bei der Auswertung
von links nach rechts das "-" als Zeichen behandelt wird. Deshalb: "mult (-1) 1
".
Rechts-Assoziativität der Typbindung | |||
---|---|---|---|
mult :: | Float -> | Float -> | Float |
multipliziere Wert von b | Ordne Ausdruck Wert von a zu | Neuer Ausdruck | |
mult2 :: | Float -> | (Float->Float) | |
multipliziere Wert von b | Speichere Wert von a als neuen Ausdruck |
Die Anwendung einer Funktion ist links-assoziativ, die Funktion wird von links nach rechts auf die Parameter
angewendet. Somit werden die aktuellen Parameter gemäß der Reihenfolge der formellen in die Funktionsgleichung eingesetzt.
Die entspricht der Äquivalenz mathematischer Funktionen
bei links-assoziativer Zuordnung:
Gegeben seien die algebraischen Funktionen f und g mit
Die Typen dieser beiden Ausdrücke Float->Float->Float und Float->(Float->Float) sind
wegen der Rechts-Assoziativität der Typsignaturen äquivalent. Die Auswertung erfolgt dabei wie
bei arithmetischen Funktionen von innen nach außen:
Aufgrund der Links-Assoziativität der Funktionsanwendung ist folgender Aufruf äquivalent:
Die Bezeichnung rührt vom Namen des vermeintlichen Entdeckers dieser Funktionen her,
"Curry Haskell", nach auch die Programmiersprache benannt wurde. Praktisch kann mit "Curried Functions" kann das Prinzip der "partiellen Anwendung" von Funktionen
realisiert werden. 1.4 Funktionsanwendung
f:x->z ;
g:x->y ;
Dann gilt:
h = f(g(x)) <=> h:(x->y)->z <=> h:x->y->z ;
Praktische Anwendung von Assoziativität und Äquivalenz (HUGS98)
HaskFuncs> mult2 1 2
2.0
HaskFuncs> (mult2 1) 2
2.0
HaskFuncs>
=> h=f(g(x)) <=> h:(x->y)->z
"Curried Functions"
Eine Funktion mit f mit n Parametern kann mit Hilfe einer "Curried Function"
auch als eine Funktion g mit einem Parameter angegeben werden, welche eine Funktion
mit n-1 Parametern zurückliefert. Die oben aufgelisteten Beispiel-Funktionen
"mult" und "mult2" sind "Curried Functions".
In abstrakter Darstellung lautet ein Aufruf der Funktion "mult2":mult2 FloatExp1 FloatExp2
, wobei "FloatExp1" und "FloatExp2" Ausdrücke vom Typ Float seien.(mult2 FloatExp1) FloatExp2