Organisation Grundlagen Haskell GHC Typen Funktionen Programmierung und Modellierung mit Haskell Einführung Martin Hofmann Steffen Jost LFE Theoretische Informatik, Institut für Informatik, Ludwig-Maximilians Universität, München 7. April 2014 Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-1 Organisation Grundlagen Haskell GHC Typen Funktionen Organisation Vorlesung Anmeldung zur Vorlesung per UniworX zwingend Umfang: 3 SWS, d.h. einige Vorlesungstermine entfallen; Newsfeed der Vorlesungshomepage beachten! https://www.tcs.ifi.lmu.de/lehre/ss-2014/promo/promo Übungen Teilnahme freiwillig, aber empfehlenswert UniworX Anmeldung zur Übungsgruppe zwingend Hausübung bringen prozentual Bonuspunkte zur Klausur x% Hausübung bringen x% des Bonus; Bonus entscheidet nicht über bestehen Beginn der Übung in 2. Semesterwoche Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-2 Organisation Grundlagen Haskell GHC Typen Funktionen Inhalt der Vorlesung Progammierung und Modellierung Funktionsbegriff, Basistypen Listen, Pattern Matching Rekursion und Terminierung Induktion & Korrektheitsbeweise Benutzerdefinierte Datentypen Tiefen- & Breitensuche Laufzeitbetrachtungen Polymorphie, Typklassen und Module Funktionen höherer Ordnung Typisierung & Typinferenz IO, Monaden & Funktoren Verzögerte Auswertung Semantik Parallele Auswertung Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-3 Organisation Grundlagen Haskell GHC Typen Funktionen Literatur Die Vorlesung richtet sich nach folgenden Quellen: Buch/Online Programming in Haskell by Graham Hutton B Learn You a Haskell for Great Good! by Miran Lipovača B O A Gentle Introduction To Haskell by Paul Hudak, John O Peterson, Joseph Fasel Real World Haskell by Bryan O’Sullivan, Don Stewart, B O John Goerzen School of Haskell by FPComplete O Haskell Wiki O so wie ältere Skripte des Lehrstuhls TCS Links/ISBN der Quellen, Skript ⇒ Vorlesungshomepage Weitere wichtige Online-Quelle: www.haskell.org Haskell-Platform: GHC Kompiler & Interpreter, Dokumentation der Standardbibliotheken, Hoogle Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-4 Organisation Grundlagen Haskell GHC Typen Funktionen Was ist Informatik? Von franz. informatique (= information + mathématiques). Engl.: computer science, auch informatics. DUDEN Informatik: Wissenschaft von der systematischen Verarbeitung von Informationen, besonders der automatischen Verarbeitung mit Computern. Gesellschaft f. Inf. (GI): Wissenschaft, Technik und Anwendung der maschinellen Verarbeitung und Übermittlung von Informationen. Association vor Computing Machinery (ACM): Systematic study of algorithms and data structures. Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-5 Organisation Grundlagen Haskell GHC Typen Funktionen Teilbereiche der Informatik Technische Informatik Aufbau und Wirkungsweise von Computern Praktische Informatik Konstruktion von Informationsverarbeitungssystemen sowie deren Realisierung auf Computern Theoretische Informatik Theoretische und verallgemeinerte Behandlungen von Fragen und Konzepten der Informatik Angewandte Informatik Verbindung von Informatik mit anderen Wissenschaften Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-6 Organisation Grundlagen Haskell GHC Typen Funktionen Typische Arbeitsgebiete Algorithmen und Komplexität Betriebssysteme Bioinformatik Datenbanken Grafik Medieninformatik Programmiersprachen und Compiler Rechnerarchitektur und Rechnernetze Robotik Simulation Softwareentwicklung Spezifikation, Verifikation, Modellierung Wirtschaftsinformatik Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-7 Organisation Grundlagen Haskell GHC Typen Funktionen Imperativ vs. Deklarativ Imperative Sprachen (Assembler, C, Java, etc.) orientieren sich an den Fähigkeiten der Maschine. Programmierung wird durch Abstraktion vieler Einzelschritte vereinfacht (z.B. Schleifen). Funktionale Programmierung ist dagegen deklarativ: Spezifiziere was berechnet werden soll, nicht wie es berechnet wird! Charakteristische Eigenschaft deklarativer Sprachen ist die Church-Rosser Eigenschaft: Die Reihenfolge der Auswertung ist unerheblich für das Ergebnis der Berechnung ist. Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-8 Organisation Grundlagen Haskell GHC Typen Funktionen Imperativ vs. Deklarativ Imperative Sprachen (Assembler, C, Java, etc.) orientieren sich an den Fähigkeiten der Maschine. Programmierung wird durch Abstraktion vieler Einzelschritte vereinfacht (z.B. Schleifen). Funktionale Programmierung ist dagegen deklarativ: Spezifiziere was berechnet werden soll, nicht wie es berechnet wird! Charakteristische Eigenschaft deklarativer Sprachen ist die Church-Rosser Eigenschaft: Die Reihenfolge der Auswertung ist unerheblich für das Ergebnis der Berechnung ist. Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-8 Organisation Grundlagen Haskell GHC Typen Funktionen Imperativ vs. Deklarativ Deklarative Sprachen sind fast immer durch die Sprache der Mathematik motiviert: Prädikaten-Logik Relationale Algebra λ-Kalkül ⇒ ⇒ ⇒ Prolog SQL Haskell Rein deklarative Sprachen in der Praxis jedoch oft problematisch, da der Ressourcenverbrauch eines Programmes (Speicherplatz, Zeit, etc.) kritisch vom wie abhängt. (Prolog, SQL ohne join). Funktionale Programmierung geht einen Mittelweg: Die Berechnung bleibt deterministisch wir kümmern uns nur nicht so sehr darum Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-9 Organisation Grundlagen Haskell GHC Typen Funktionen Imperativ vs. Deklarativ Deklarative Sprachen sind fast immer durch die Sprache der Mathematik motiviert: Prädikaten-Logik Relationale Algebra λ-Kalkül ⇒ ⇒ ⇒ Prolog SQL Haskell Rein deklarative Sprachen in der Praxis jedoch oft problematisch, da der Ressourcenverbrauch eines Programmes (Speicherplatz, Zeit, etc.) kritisch vom wie abhängt. (Prolog, SQL ohne join). Funktionale Programmierung geht einen Mittelweg: Die Berechnung bleibt deterministisch wir kümmern uns nur nicht so sehr darum Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-9 Organisation Grundlagen Haskell GHC Typen Funktionen Referentielle Transparenz Wichtige Eigenschaft deklarativer Sprachen: Referentielle Transparenz Wert einer Variablen ist unveränderlich Aufrufe mit gleichen Argumenten liefern gleiches Ergebnis Keine Seiteneffekte! Konsequenzen: Programme lokal verständlich und kompositional Testen/Verifikation reduziert sich auf Gleichheitsschließen Kompiler kann sehr aggressiv optimieren Parallele Berechnung einfacher Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-10 Organisation Grundlagen Haskell GHC Typen Funktionen Vor-/Nachteile Funktionaler Programm. FP ist alt, doch kaum verbreitet?! λ-Kalkül 1930s, Lisp 1958 Völlig andere (mathematische) Denkweise Verlust von “Kontrolle” gegenüber herkömmlichen Sprachen, Maschinen-nahe Hand-Optimierung schwierig durchführbar Geringe kommerzielle Unterstützung IDE, Debugger,. . . Kompiler “meckert viel” bevor man testen kann Aber: “Well-typed programs can’t go wrong!”, R.Milner Gut geeignet für Programmanalyse “Einschränkungen” vorteilhaft für Mehrpersonen-Projekte Kurzer Code ⇒ kurze Entwicklungszeit; Wartbarkeit Funktionale Merkmale inzwischen in vielen anderen Sprachen z.B. Funktionen höherer Ordnung, Anonyme Funktionen, Java GC optimiert auf kurzlebige, statische Objekte, etc. Neues kommerzielle Interesse wegen Multi-Cores “The Downfall of Imperative Programming”, Milewski Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-11 Organisation Grundlagen Haskell GHC Typen Funktionen Vor-/Nachteile Funktionaler Programm. FP ist alt, doch kaum verbreitet?! λ-Kalkül 1930s, Lisp 1958 Völlig andere (mathematische) Denkweise Verlust von “Kontrolle” gegenüber herkömmlichen Sprachen, Maschinen-nahe Hand-Optimierung schwierig durchführbar Geringe kommerzielle Unterstützung IDE, Debugger,. . . Kompiler “meckert viel” bevor man testen kann Aber: “Well-typed programs can’t go wrong!”, R.Milner Gut geeignet für Programmanalyse “Einschränkungen” vorteilhaft für Mehrpersonen-Projekte Kurzer Code ⇒ kurze Entwicklungszeit; Wartbarkeit Funktionale Merkmale inzwischen in vielen anderen Sprachen z.B. Funktionen höherer Ordnung, Anonyme Funktionen, Java GC optimiert auf kurzlebige, statische Objekte, etc. Neues kommerzielle Interesse wegen Multi-Cores “The Downfall of Imperative Programming”, Milewski Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-11 Organisation Grundlagen Haskell GHC Typen Funktionen Vor-/Nachteile Funktionaler Programm. FP ist alt, doch kaum verbreitet?! λ-Kalkül 1930s, Lisp 1958 Völlig andere (mathematische) Denkweise Verlust von “Kontrolle” gegenüber herkömmlichen Sprachen, Maschinen-nahe Hand-Optimierung schwierig durchführbar Geringe kommerzielle Unterstützung IDE, Debugger,. . . Kompiler “meckert viel” bevor man testen kann Aber: “Well-typed programs can’t go wrong!”, R.Milner Gut geeignet für Programmanalyse “Einschränkungen” vorteilhaft für Mehrpersonen-Projekte Kurzer Code ⇒ kurze Entwicklungszeit; Wartbarkeit Funktionale Merkmale inzwischen in vielen anderen Sprachen z.B. Funktionen höherer Ordnung, Anonyme Funktionen, Java GC optimiert auf kurzlebige, statische Objekte, etc. Neues kommerzielle Interesse wegen Multi-Cores “The Downfall of Imperative Programming”, Milewski Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-11 Organisation Grundlagen Haskell GHC Typen Funktionen Haskell Effektfreie funktionale Sprache mit verzögerter Auswertung für universellen Einsatz Benannt nach Haskell Curry (1900-82), Logiker Standards: Haskell98 und Haskell2010 Viele verschiedene Implementierung verfügbar; wichtigste ist die Haskell Platform mit “batteries included”: Kompiler, Interpreter und zahlreichen Bibliotheken GHC : Glasgow/Glorious Haskell Compiler Hammond, 1989 akutelle Versionen mehrmals pro Jahr Hauptentwickler erhielten 2011 ACM SIGPLAN Programming Languages Software Award: Simon Peyton-Jones Microsoft Research Cambridge Simon Marlow Facebook Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-12 Organisation Grundlagen Haskell GHC Typen Funktionen Warum gerade Haskell? Für einen großen Teil der Vorlesungsinhalte spielt es keine Rolle, welche funktionale Sprache wir betrachten. Haskell ist im Gegensatz zu vielen anderen funktionalen Sprachen (z.B. SML) rein funktional, d.h. referentielle Transparenz gilt uneingeschränkt Haskell hat ein starkes statisches Typsystem Viel aktuelle Dokumentation verfügbar Kommerzielle Unterstützung IDE auf fpcomplete.com Arithmetik mit beliebiger Präzision verfügbar Gute Unterstützung für Parallelität Produziert “flotten” Code Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-13 Organisation Grundlagen Haskell GHC Typen Funktionen GHC In der Vorlesung arbeiten wir mit der Haskell Platform, welche aus GHC, Bibliotheken und Dokumentation besteht. Die meiste Dokumentation ist aber auch online verfügbar, wie zum Beispiel http://www.haskell.org/ghc/docs/latest/html/libraries/ Glasgow Haskell Kompiler (GHC) kennt zwei Arbeitsweisen: GHC Normaler Kompiler. Ein Programm wird in mehreren Dateien geschrieben und mithilfe des GHC in ein ausführbares Programm übersetzt. GHCi Interpreter Modus: Man gibt Definitionen ein und GHCI wertet diese sofort aus und zeigt den Wert an. Wir befassen uns zunächst primär mit dem interaktiven Modus. Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-14 Organisation Grundlagen Haskell GHC Typen Funktionen GHCI > ghci GHCi, version 7.6.3: http://www.haskell.org/ghc/ Loading package ghc-prim ... linking ... done. Loading package integer-gmp ... linking ... done. Loading package base ... linking ... done. Prelude> 1 + 2 3 Prelude> 3 + 4 * 5 23 Prelude> (3 + 4) * 5 35 Prelude> Der Text hinter dem Prompt Prelude> wurde vom Benutzer getätigt, alles andere sind Ausgaben von GHCi. Der Prompt gibt Martin Hofmann, Steffen Jost Programmierung und Modellierung per Default alle geladenen Bibliotheken (Module) an. 01-15 Organisation Grundlagen Haskell GHC Typen Funktionen GHCI > ghci +RTS -M1g GHCi, version 7.6.3: http://www.haskell.org/ghc/ Loading package ghc-prim ... linking ... done. Loading package integer-gmp ... linking ... done. Loading package base ... linking ... done. Prelude> 1 + 2 3 Prelude> 3 + 4 * 5 23 Prelude> (3 + 4) * 5 35 Prelude> Der Text hinter dem Prompt Prelude> wurde vom Benutzer getätigt, alles andere sind Ausgaben von GHCi. Der Prompt gibt Martin Hofmann, Steffen Jost Programmierung und Modellierung per Default alle geladenen Bibliotheken (Module) an. 01-15 Organisation Grundlagen Haskell GHC Typen Funktionen GHCI Der Interpreter wertet alle eingegebenen Ausdrücke aus. Mit den Pfeiltasten kann von vorherige Eingaben durchblättern Zur Steuerung des Interpreters stehen Befehle zur Verfügung, welche alle mit einem Doppelpunkt beginnen, z.B. :? für die Hilfe. Alle Befehle kann man abkürzen. So kann man den Interpreter sowohl mit :quit also auch mit :q verlassen. Für uneindeutige Abkürzungen gibt es voreingestellte Defaults. Auch für GHCi macht es Sinn, Programmdefinitionen mit einem gewöhnlichen Texteditor in eine separate Datei speichern und dann in den Interpreter zu laden, um nicht immer alles neu eintippen zu müssen. :l datei .hs -- lade Definition aus Datei datei .hs :r -- erneut alle offenen Dateien einlesen Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-16 Organisation Grundlagen Haskell GHC Typen Funktionen Fallstricke Haskell beachtet Groß-/Kleinschreibung! Haskell ist “whitespace”-sensitiv: Veränderungen an Leerzeichen, Tabulatoren und Zeilenumbruch können Fehler verursachen! Grundsätzlich gilt: Beginnt die nächste Zeile in . . . Spalte weiter rechts: vorheriger Zeile geht weiter gleicher Spalte: nächstes Element eines Blocks beginnt Spalte weiter links: Block beendet Daraus folgt: Alle Top-level Definition müssen in gleicher Spalte beginnen Einrückung kann viele Klammern sparen Tabulatorweite in Editor und GHC muss übereinstimmen Anstatt Einrückung können auch { } und ; benutzt werden. Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-17 Organisation Grundlagen Haskell GHC Typen Funktionen Ausdrücke & Werte GHCi wertet Ausdrücke aus. Ein Ausdruck kann atomar sein, wie z.B. 1337, ’a’ zusammengesetzt sein, wie z.B. 12+1, 27 * (7 + 5) Ein Ausdruck kann also aus mehreren Unterausdrücken bestehen. Mit Klammern können wir explizit angeben, in welcher Reihenfolge ein Ausdruck aus seinen Unterausdrücken zusammengesetzt ist. Ein Ausdruck hat (meistens) auch einen Wert; so ist 13 der Wert des Ausdrucks 12+1. Jeder korrekt gebildete Ausdruck besitzt einen Typ. Zum Beispiel: der Ausdruck 12+1 hat den Typ Int. Wir schreiben kurz 12+1 :: Int Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-18 Organisation Grundlagen Haskell GHC Typen Funktionen Einfache Typen Zusammengesetze Typen Typen Ein Typ ist eine Menge von Werten; so bezeichnet der Typ Int meistens die Menge der ganzen Zahlen von −229 bis 229 − 1. Haskell-Syntax: Typnamen beginnen immer mit Großbuchstaben Typvariablen beginnen immer mit Kleinbuchstaben GHCI Befehl :t zeigt Typ eines Ausdrucks: Prelude > :t ’a’ ’a’ :: Char e :: A gelesen als “Ausdruck e hat Typ A” Mit dem Befehl :set +t wird der Typ jedes ausgewerteten Ausdrucks angezeigt, mit :unset +t stellt man das wieder ab. ⇒ dauerhaft einstellbar in ghci.conf Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-19 Organisation Grundlagen Haskell GHC Typen Funktionen Einfache Typen Zusammengesetze Typen Wichtige Numerische Typen Int Ganze Zahlen (“fixed precision integers”), maschinenabhängig, mindestens von −229 bis 229 − 1. Es wird nicht auf Überläufe geprüft. Integer Ganze Zahlen beliebiger Größe “arbitrary precision integers” Float Fließkommazahlen mindestens nach IEEE standard “single-precision floating point numbers” Double Fließkommazahlen mit mindestens doppelter Genauigkeit nach IEEE standard “double-precision floating point numbers” Rational Rationale Zahlen beliebiger Genauigkeit, werden mit dem Prozentzeichen konstruiert: 1 % 5 ≈ 0.2 ’%’ nicht im Prelude-Modul enthalten Haskell kennt viele weitere numerische Datentypen, z.B. komplexe Zahlen, Uhrzeiten oder Festkommazahlen. Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-20 Organisation Grundlagen Haskell GHC Typen Funktionen Einfache Typen Zusammengesetze Typen Wichtige Typen Neben Zahlen gibt es noch weitere wichtige grundlegende Typen: Bool Boole’sche (logische) Wahrheitswerte: True und False Char Unicode Zeichen, z.B. ’q’. Diese werden immer in Apostrophen eingeschlossen. String Zeichenketten, z.B. "Hallo!". Diese werden immmer in Anführungszeichen eingeschlossen. Haskell ist so knapp wie nötig formuliert. Viele Dinge, welche in anderen Sprachen “speziell” oder “eingebaut” sind, werden in Haskell in einer gewöhnlichen Bibliothek definiert. Von diesen drei Typen ist lediglich Char etwas grundlegender, die beiden anderen kann man leicht selbst definieren; doch dazu lernen wir später noch mehr. Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-21 Organisation Grundlagen Haskell GHC Typen Funktionen Einfache Typen Zusammengesetze Typen Kartesisches Produkt Ein Beispiel für einen zusammengesetzten Typen hat als Vorlage aus der Mathematik das kartesische Produkt: Aus den Mengen A1 und A2 Mengen bildet man als kartesisches Produkt die Menge A1 × A2 = {(a1 , a2 ) | a1 ∈ A1 und a2 ∈ A2 } Beispiel: (5, 8) ∈ N × N Definition (Kartesisches Produkt) Sind A1 , . . . An Mengen, so ist das kartesische Produkt definiert als A1 × · · · × An = (a1 , . . . , an ) | ai ∈ Ai für i = 1 . . . n Die Elemente von A1 ×, . . . , ×An heißen allgemein n-Tupel, spezieller auch Paare, Tripel, Quadrupel, Quintupel, Sextupel,. . . Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-22 Organisation Grundlagen Haskell GHC Typen Funktionen Einfache Typen Zusammengesetze Typen Tupel In Haskell schreiben wir das genau so hin, lediglich im Typ verwenden wir anstelle des Symbols × ebenfalls Klammern und Kommas. Aus Z × Z wird also (Integer,Integer): Prelude > :set +t Prelude > (7 ,6) (7 ,6) it :: (Integer , Integer ) Prelude > (42,’a ’) (42,’a ’) it :: (Integer , Char) Prelude > (True ,4.5 ,"Hi!") (True ,4.5 ,"Hi!") it :: (Bool , Double , String ) Prelude > Zusammengesetzten Typen und deren Werte können wir ganz genauso wie jeden anderen Typen verwenden. Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-23 Organisation Grundlagen Haskell GHC Typen Funktionen Einfache Typen Zusammengesetze Typen Listen Einer der wichtigsten Typen in Haskell sind Listen, also geordnete Folgen von Werten. Listen schreiben wir in eckigen Klammern, wobei die Elemente durch Kommas getrennt werden: [1 ,2 ,3] :: [Int] [1 ,2 ,2 ,3 ,3 ,3] :: [Int] ["Hello "," World ","!"] :: [ String ] Im Gegensatz zu einem Tupel wissen wir anhand des Typen nicht, wie viele Werte eine Liste enthält. Eine Liste kann sogar ganz leer sein, geschrieben []. Allerdings wissen wir, dass alle Elemente einer Liste den gleichen Typ haben — diesen schreiben wir ebenfalls in eckigen Klammern um den Listentyp hinzuschreiben; Listen sind daher homogene Datenstrukturen. Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-24 Organisation Grundlagen Haskell GHC Typen Funktionen Einfache Typen Zusammengesetze Typen Listen Listen und Tupel kann man beliebig ineinander verschachteln: [(1,’a’),(2,’z’),(-4,’w ’)] :: [( Integer , Char )] [[1 ,2 ,3] ,[] ,[4]] :: [[ Integer ]] (4.5 ,[( True ,’a ’ ,[5 ,7] ,())]) :: (Double , [(Bool , Char , [ Integer ], ())]) Achtung: [] und [[]] und [[],[]] und [[[]]] und [[],[[]]] sind alles verschiedene Werte. Das 0-Tupel ist ebenfalls erlaubt: () :: (). Der Typ () wird als Unit-Typ bezeichnet, und hat nur den einzigen Wert (). Aus dem Kontext wird fast immer klar, ob mit () der Typ oder der Wert gemeint ist. Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-25 Organisation Grundlagen Haskell GHC Typen Funktionen Einfache Typen Zusammengesetze Typen Listen Listen und Tupel kann man beliebig ineinander verschachteln: [(1,’a’),(2,’z’),(-4,’w ’)] :: [( Integer , Char )] [[1 ,2 ,3] ,[] ,[4]] :: [[ Integer ]] (4.5 ,[( True ,’a ’ ,[5 ,7] ,())]) :: (Double , [(Bool , Char , [ Integer ], ())]) Achtung: [] und [[]] und [[],[]] und [[[]]] und [[],[[]]] sind alles verschiedene Werte. Das 0-Tupel ist ebenfalls erlaubt: () :: (). Der Typ () wird als Unit-Typ bezeichnet, und hat nur den einzigen Wert (). Aus dem Kontext wird fast immer klar, ob mit () der Typ oder der Wert gemeint ist. Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-25 Organisation Grundlagen Haskell GHC Typen Funktionen Einfache Typen Zusammengesetze Typen Listen Listen und Tupel kann man beliebig ineinander verschachteln: [(1,’a’),(2,’z’),(-4,’w ’)] :: [( Integer , Char )] [[1 ,2 ,3] ,[] ,[4]] :: [[ Integer ]] (4.5 ,[( True ,’a ’ ,[5 ,7] ,())]) :: (Double , [(Bool , Char , [ Integer ], ())]) Achtung: [] und [[]] und [[],[]] und [[[]]] und [[],[[]]] sind alles verschiedene Werte. Das 0-Tupel ist ebenfalls erlaubt: () :: (). Der Typ () wird als Unit-Typ bezeichnet, und hat nur den einzigen Wert (). Aus dem Kontext wird fast immer klar, ob mit () der Typ oder der Wert gemeint ist. Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-25 Organisation Grundlagen Haskell GHC Typen Funktionen Einfache Typen Zusammengesetze Typen Typabkürzungen Der Typ String ist nur eine Abkürzung für eine Char-Liste: type String = [Char] Solche Abkürzungen darf man genau so auch selbst definieren: Hinter dem Schlüsselwort type schreibt meinen einen frischen Namen, der mit einem Großbuchstaben beginnt und hinter dem Gleichheitszeichen folgt ein bekannter Typ, z.B. type MyWeirdType = (Double ,[( Bool , Integer )]) Für die Ausführung von Programmen ist dies unerheblich. Typabkürzungen dienen primär zur Verbesserung der Lesbarkeit. Leider ignoriert GHC/GHCi Typabkürzungen meistens, d.h. GHCi gibt fast immer [Char] anstelle von String aus. Es gibt noch weitere zusammengesetzte Typen, z.B. Records, Funktionstypen, etc. Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-26 Organisation Grundlagen Haskell GHC Typen Funktionen in der Mathematik in Haskell Funktionen Definition (Funktion) Für zwei Mengen A und B ist eine (totale) Funktion f von A nach B eine Zuordnung, welche jedem Element x ∈ A genau ein Element y ∈ B zuordnet; geschrieben f (x) = y . Die Menge A bezeichnen wir als den Definitionsbereich von f , die Menge B als Zielbereich. Für eine Funktion f von A nach B schreiben wir kurz: f : A → B. Funktionsanwendung wird auch gerne ohne Klammer in Präfixnotation f x geschrieben, die Postfixnotation x f findet dagegen seltener Verwendung. Den Definitionsbereich einer Funktion f (engl. Domain) bezeichnen wir üblicherweise mit dom(f ). Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-27 Organisation Grundlagen Haskell GHC Typen Funktionen in der Mathematik in Haskell Beispiel: Funktionen Totale Funktionen Minus : Z → Z Nachfolgerfunktion f x Signumfunktion +1 falls sgn arg = 0 falls −1 falls =x +1:N→N x >0 x = 0 : R → {−1, 0, +1} x <0 Partielle Funktionen √ Wurzelfunktion · : R → R mit Definitionsbereich R+ Kehrwert kw x = 1/x : R → R mit Definitionsbereich R \ {0} ( 2x x > 1 foo x = :N→N 0 x <1 mit Definitionsbereich N \ {−1, 0, +1} Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-28 Organisation Grundlagen Haskell GHC Typen Funktionen in der Mathematik in Haskell Partielle Funktionen Definition (Partielle Funktion) Eine partielle Funktion f : A → B ordnet nur einer Teilmenge A0 ⊂ A einen Wert aus B zu, und ist ansonsten undefiniert. In diesem Falle bezeichnen wir A als Quellbereich und A0 als Definitionsbereich. Ob eine Funktion partiell oder total ist, kann man nicht immer leicht feststellen. Wir sprechen von partiellen Funktionen, wenn bei der Berechnung einer Funktion für ein bestimmtes Argument ein Fehler auftritt Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-29 Organisation Grundlagen Haskell GHC Typen Funktionen in der Mathematik in Haskell Beispiel: Funktionen Totale Funktionen Minus : Z → Z Nachfolgerfunktion f x Signumfunktion +1 falls sgn arg = 0 falls −1 falls =x +1:N→N x >0 x = 0 : R → {−1, 0, +1} x <0 Partielle Funktionen √ Wurzelfunktion · : R → R mit Definitionsbereich R+ Kehrwert kw x = 1/x : R → R mit Definitionsbereich R \ {0} ( 2x x > 1 foo x = :N→N 0 x <1 mit Definitionsbereich N \ {−1, 0, +1} Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-30 Organisation Grundlagen Haskell GHC Typen Funktionen in der Mathematik in Haskell Anonyme Funktionen Merkwürdig: √ · :: R → R Was bedeutet der Punkt? Es ist oft praktisch, simplen Funktionen keinen besonderen Namen zu geben, bzw. die Wurzelfunktion hat ja bereits ein eigenes Symbol. Aus dem Lambda-Kalkül (Alonzo Church, 1936), der mathematischen Grundlage der funktionalen Programmierung, nehmen wir daher die λ-Notation für anonyme Funktionen: Nachfolgerfunktion λx . x + 1 √ Wurzelfunktion λy . y In Haskell schreiben wir anstelle von λ einfach einen Rückstrich \ \x -> x + 1 \y -> sqrt y Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-31 Organisation Grundlagen Haskell GHC Typen Funktionen in der Mathematik in Haskell Funktionen mit mehreren Argumenten Eine Funktion, deren Quellbereich ein n-stelliges kartesisches Produkt ist, nennt man eine Funktion der Stelligkeit n, oder auch n-stellige Funktion “n-ary function”,“arity”. f :: N × N → N f (x, y ) = x + 2y 2 Für die Anwendung zweistelliger Funktionen wird öfters die Infixnotation verwendet: xfy Bekannte Beispiele für zweistellige Funktionen mit gebräuchlicher Infixnotation sind +, −, ∗, /. Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-32 Organisation Grundlagen Haskell GHC Typen Funktionen in der Mathematik in Haskell Funktionen mit mehreren Argumenten Eine Funktion, deren Quellbereich ein n-stelliges kartesisches Produkt ist, nennt man eine Funktion der Stelligkeit n, oder auch n-stellige Funktion “n-ary function”,“arity”. f :: N × N → N f (x, y ) = x + 2y 2 Für die Anwendung zweistelliger Funktionen wird öfters die Infixnotation verwendet: xfy Bekannte Beispiele für zweistellige Funktionen mit gebräuchlicher Infixnotation sind +, −, ∗, /. Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-32 Organisation Grundlagen Haskell GHC Typen Funktionen in der Mathematik in Haskell Funktionen mit mehreren Argumenten Eine Funktion, deren Quellbereich ein n-stelliges kartesisches Produkt ist, nennt man eine Funktion der Stelligkeit n, oder auch n-stellige Funktion “n-ary function”,“arity”. f :: N × N → N f (x, y ) = x + 2y 2 Für die Anwendung zweistelliger Funktionen wird öfters die Infixnotation verwendet: xfy Bekannte Beispiele für zweistellige Funktionen mit gebräuchlicher Infixnotation sind +, −, ∗, /. Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-32 Organisation Grundlagen Haskell GHC Typen Funktionen in der Mathematik in Haskell Funktionen in Haskell In Haskell schreiben wir Funktion ganz natürlich hin: succ :: Int -> Int succ x = x + 1 Wir definieren eine Funktion mit dem Namen succ, welche eine ganze Zahl auf Ihren Nachfolger abbildet. Den Namen des Argumentes, hier x, können wir frei wählen. “Sprechende” Namen empfehlen sich. Die erste Zeile, also die Angabe der Typsignatur der Funktion ist optional, da GHC den Typ auch automatisch inferieren kann. Man sollte immer explizite Typsignaturen hinschreiben, denn. . . . . . Typsignaturen sind eine hilfreiche Dokumentation . . . helfen dabei, Fehlermeldungen leserlicher zu machen . . . können Programme manchmal effizienter machen Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-33 Organisation Grundlagen Haskell GHC Typen Funktionen in der Mathematik in Haskell Mehrstellige Funktionen Mehrstellige Funktionen können wir auf zwei Arten definieren: 1-stellige Funktion mit Kartesischem Produkt foo :: (Int ,Int) -> Int foo (x,y) = (x + 1) * y Hier verwenden wir ganz einfach Tupel Echte n-stellige Funktion bar :: Int -> (Int -> Int) bar x y = (x + 1) * y Hier schreiben wir einfach alle Argumente durch Leerzeichen getrennt hintereinander. Die zweite Variante wird oft bevorzugt; doch da eine Funktion immer nur einen einzigen Wert zurück liefern kann, bietet es sich manchmal an, Tupel zu verwenden. Man kann auch leicht wechseln, Stichwort “Currying”. Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-34 Organisation Grundlagen Haskell GHC Typen Funktionen in der Mathematik in Haskell Funktionsanwendung Die Funktionsanwendung verwendet in Haskell primär die Präfixnotation, d.h. man schreibt hinter dem Namen der Funktion einfach alle Argumente, durch Leerzeichen getrennt: Prelude > 6 succ 5 Prelude > foo (2 ,7) 21 Prelude > bar 1 8 16 Dies kann man auch mithilfe von Klammern verschachteln: Prelude > bar (succ 5) 2 14 Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-35 Organisation Grundlagen Haskell GHC Typen Funktionen in der Mathematik in Haskell Infixnotation in Haskell Haskell bietet ebenfalls die Infixnotationen an, um die Lesbarkeit des Codes zu erhöhen. Der Programmierer gibt bei der Funktionsdefinition an, welche Notation er bevorzugt: infixl 6 + (+) :: Int -> Int (+) x succ :: Int -> Int succ x = x + 1 infixl oder infixr und die Zahl dahinter zeigen Haskell, in welcher Reihenfolge mehrere Unterausdrücke ohne explizite Klammerung zu lesen sind. So wird zum Beispiel die Punkt-vor-Strich Regel eingehalten: infixl 7 * Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-36 Organisation Grundlagen Haskell GHC Typen Funktionen in der Mathematik in Haskell Infixnotation in Haskell Zwischen Infix- und Präfixnotation kann man jederzeit auch ad hoc wechseln: Mit Klammern macht man aus einer Infix-Funktion eine gewöhnliche Präfix-Funktion: Prelude > (+) 1 2 3 Mit Rückstrichen “backquotes” macht man aus einer Funktion in Präfixnotation eine Infix-Funktion: Prelude > 1 ‘bar ‘ 8 16 Man verwendet die Notation, welche die Lesbarkeit erhöht. Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-37 Organisation Grundlagen Haskell GHC Typen Funktionen in der Mathematik in Haskell Funktionstypen Der Typ einer Funktion ist ein zusammengesetzter Funktionstyp, der immer aus genau zwei Typen mit einem Pfeil dazwischen besteht. Klammerkonvention Funktionstypen sind implizit rechtsgeklammert, d.h. man darf die Klammern manchmal weglassen: Int -> Int -> Int wird gelesen als Int -> (Int -> Int) Entsprechend ist die Funktionsanwendung implizit linksgeklammert: bar 1 8 wird gelesen als (bar 1) 8 Das bedeutet: (bar 1) ist eine Funktion des Typs Int -> Int! Funktionen sind also normale Werte in einer funktionalen Sprache! Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-38 Organisation Grundlagen Haskell GHC Typen Funktionen in der Mathematik in Haskell Zusammenfassung Haskell ist eine universelle Programmiersprache “Haskell Platform” installieren, nicht nur GHC Anzeige von Typen ggf. in ghci.conf dauerhaft aktivieren ghc/ghci mit Option +RTS -M1g starten, um Speicherverbrauch zu begrenzen Haskell ist White-Space und Case sensitiv: Einrückung beachten! Editor sollte Tabulatoren in Leerzeichen wandeln, oder Tabulator-weite von Editor und GHC muss übereinstimmen Interpreter Befehle beginnen mit Doppelpunkt, z.B. :quit Funktionen bekommen immer nur ein Argument; Mehrstellige Funktionen: Entweder Produkte von Argumenten als n-Tupel oder Ergebnis ist Funktion, welche nächstes Argument verarbeitet Martin Hofmann, Steffen Jost Programmierung und Modellierung 01-39