Haskell-Kurs Tag 2 Mehr Typen Zunaechst wieder Prelude> :set +t um Typinformationen bei der Auswertung von Ausdruecken zu bekommen. Am ersten Tag haben wir hauptsaechlich mit ganzzahligen Werten (Integer) und Fliesskommazahlen (Double) gerechnet. Wir haben auch schon Beispiele fuer Zeichen und Zeichenketten gesehen, zur Erinnerung: Prelude> 'c' Prelude> "Hallo" Es gibt aber viel mehr Datentypen: In Haskell hat jeder Ausdruck einen Typ, und jeder Teilausdruck ebenfalls. Wir haben bereits mit einer ganzen Reihe von Funktionen und Operatoren gearbeitet, wie etwa "sin" oder "+". Was haben sie fuer einen Typ? Probieren wir einmal Prelude> sin Wir bekommen eine Fehlermeldung. GHCi sagt uns No instance for (Show (a -> a)) und noch viel mehr, waehrend Hugs uns mit ERROR - Cannot find "show" function for: *** Expression : sin *** Of type : Double -> Double beglueckt. Um den Fehler zu erklaeren, werden wir versuchen zu erkennen, warum ein Fehler auftritt. Wenn man einen Haskell-Ausdruck am Interpreter-Prompt eingibt, dann wird der Ausdruck ausgewertet und das Ergebnis angezeigt. Bei dieser Ausgabe auf dem Bildschirm bedient sich der Interpreter einer speziellen Funktion "show", ueber die wir spaeter noch mehr lernen werden. Wir haben eine Funktion, naemlich "sin" eingegeben. Da die Funktion kein Argument bekommen hat, kann sie nicht weiter ausgewertet werden, daher ist die Auswertung der Funktion ist die Funktion selbst. An der Auswertung scheitert es hier also _nicht_! Das Problem tritt auf bei der Ausgabe. In Haskell gibt es keine vordefinierte Moeglichkeit, um eine Funktion auszugeben. Diesen Umstand versucht die kryptische Fehlermeldung oben in Worte zu fassen. Gluecklicherweise gibt es aber die Moeglichkeit, sich vom Interpreter den Typ von Ausdruecken anzeigen zu lassen, ohne die Auswertung und Ausgabe des Ausdruckes zu veranlassen. Dies geschieht mittels ":t" (diese Anweisungen, die mit einem Doppelpunkt beginnen, sind allesamt Kommandos an den Interpreter und haben mit der Sprache Haskell eigentlich nichts zu tun), also Prelude> :t 'c' Char Prelude> :t sin forall a. (Floating a) => a -> a (Beim Hugs fehlt das "forall a. " in der Ausgabe.) Das scheint ziemlich kompliziert, ist aber zu lesen wie eine logische Formel, wobei "Floating" ein Praedikat oder eine einstellige Relation ist. Also: Fuer alle (Typen) "a", fuer die "Floating a" gilt, haben wir eine Funktion "a -> a". Insbesondere gilt "Floating Double", daher laesst sich der Type vereinfachen zu "Double -> Double" und wir koennen die Funktion auf Werte vom Typ "Double" anwenden: Prelude> 0.5 0.5 it :: Double Prelude> sin 0.5 0.479425538604203 it :: Double Ein aehnliches Bild liefert die Funktion fuer den Absolutbetrag "abs": Prelude> :t abs forall a. (Num a) => a -> a Bis auf das Praedikat gibt es keinen Unterschied. "Num" ist ein Praedikat, das von mehr Typen erfuellt wird als "Floating", unter anderem sowohl von "Double" als auch von "Integer". Daher Prelude> abs (-2) 2 it :: Integer Prelude> abs 0.5 0.5 it :: Double Aber Prelude> abs 'c' produziert eine Fehlermeldung, im GHCi wie folgt: :1: No instance for (Num Char) arising from use of `abs' at :1 In the definition of `it': abs `c' Die relevante der vier Zeilen ist die zweite: "No instance for (Num Char)" bedeutet nichts weiter, als dass "Char" das Praedikat "Num" nicht erfuellt. Wir werden viel spaeter genauer beleuchten, was es mit Praedikaten auf sich hat und welche Typen welche Praedikate erfuellen. Bislang genuegt es, sich zu merken: Num (numerische Werte) wird von "Integer" und "Double" erfuellt Floating (Fliesskommazahlen) wird von "Double" erfuellt Schon an Tag 1 haben wir eine sehr aehnliche Fehlermeldung erzeugt, naemlich mit Prelude> 2+'c' Auch "+" ist eine Haskell-Funktion und verhaelt sich fast genauso wie "abs" und "sin", kann aber infix verwendet werden, also zwischen zwei Argumenten. Die Infix-Schreibweise ist in Haskell nur sogenannter syntaktischer Zucker, also eine Erleichterung, um die Programme schoener aussehen zu lassen. Jeder Operator ist eine ganz normale Funktion, wenn man ihn in runde Klammern einschliesst: Prelude> (+) 2 3 ist gleichbedeutend mit Prelude> 2 + 3 *** Aufgabe 1: Offenbar werden auch bei Funktionen mit mehreren Argumenten keine Klammern zur Indikation der Argumente verwendet. Die Schreibweise Prelude> (+) (2,3) etwa fuehrt zu einer sehr komplizierten Fehlermeldung (ist aber ein gueltiger Haskell-Ausdruck, wie wir spaeter sehen werden). Was fuer Vorteile koennte die erste Schreibweise haben? Probiere die folgenden Eingaben aus Prelude> :t (+) Prelude> :t (+) 2 Prelude> :t ((+) 2) 3 Prelude> ((+) 2) 3 Prelude> :t (+2) Prelude> (+2) 3 Prelude> :t (/) Prelude> :t (/2.5) Prelude> :t (2.5/) Prelude> (/2.5) 7 Prelude> (2.5/) 7 *** Lernziele Tag 2: [ ] Typinformation ohne Auswertung und Ausgabe erhaelt man mit ":t". [ ] Funktionstypen enthalten das Symbol "->" [ ] Typen haben Aehnlichkeit mit logischen Formeln: Sie koennen Praedikate, Quantifizierungen und Variablen enthalten.