Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

Eine rein funktionale Sprache

Ähnliche Präsentationen


Präsentation zum Thema: "Eine rein funktionale Sprache"—  Präsentation transkript:

1 Eine rein funktionale Sprache
Haskell Eine rein funktionale Sprache Programmiersprache der 3. Generation

2 Ein Rat vorweg An die anwesenden C-Programmierer: Vergesst am besten alles, was Ihr bisher über Programmierung und Programmiersprachen gelernt habt !!!

3 We now proudly present:

4 Übersicht Einführung Einordnen von Haskell in das Sprachen-Spektrum imperativ vs. deklarativ Beispiel eines imperativen Programms und eines deklarativen Programms Entwicklung der deklarativen Sprachen, insb. Haskell l-Kalkül, Grundlage von Haskell Einführung, Auswertung, Erweiterung, Beispiele, … Evolution der Programmiersprachen Grundkonzepte funktionaler Sprachen, insb. Haskell Typen Beispielprogramm: Kryptographie Auswertung Beispielauswertung (Tafel) Lazy Evaluation Rekursive Funktionen (mit einfachen Datenstrukturen) Kurze Übersicht über das heutige Thema, Der erste Teil wird etwas theoretischer sein und ca 20 Minuten dauern, Danach gehen wir konkrete Befehle und Typen der Programmiersprache durch und programmieren unseres erste kleine Programm

5 Das Sprachen-Spektrum

6 imperativ vs. deklarativ
Merkmale imperativer Sprachen Die Grundidee ist die des „von Neumann“ bzw. des „stored program“ Rechners. Hier werden Programme als feste Folge von Befehlen nacheinander abgearbeitet. Ein Programm beschreibt, wie etwas berechnet wird. Dies geschieht als Abfolge lokaler Speichertransformationen (Wertzuweisungen). Die Kontrollstruktur ist die Iteration (Schleife). Merkmaler deklarativer Sprachen Die Grundidee ist das l-Kalkül von Church, eine mathematische Theorie. Jede Berechnung ist das Ergebnis einer Funktion und wird durch einfache Ersetzung von Ausdrücken errechnet (Reduktion).  vgl. Auswertung Die Hauptkontrollstruktur ist die Rekursion.

7 Somit lässt sich der Hauptunterschied zusammenfassen als Motto:
WAS anstelle von WIE Der Programmierer soll nur noch angeben, was er programmieren möchte, er soll nicht mehr damit belastet werden, wie etwas genau programmiert wird. (Aber trotzdem muss er in der Lage sein dem Computer mitzuteilen, was er haben möchte.)

8 Der Quicksortalgorithmus Vergleich zwischen imperativer und funktionaler Programmierung
Implementierung in Java: private void swap(Object [] rgo, int i, int j) { Object o; o = rgo[i]; rgo[i] = rgo[j]; rgo[j] = o; } protected boolean lessThan(Object oFirst, Object oSecond) return oFirst.hashCode() < oSecond.hashCode(); { public void sort(Object [] rgo) sort(rgo, 0, rgo.length - 1); } private void sort(Object [] rgo, int nLow0, int nHigh0) int nLow = nLow0; int nHigh = nHigh0; Object oMid; if (nHigh0 > nLow0) oMid = rgo[ (nLow0 + nHigh0) / 2 ]; while(nLow <= nHigh) while((nLow < nHigh0) && lessThan(rgo[nLow], oMid)) ++nLow; while((nLow0 < nHigh) && lessThan(oMid, rgo[nHigh])) --nHigh; if(nLow <= nHigh) swap(rgo, nLow++, nHigh--); if(nLow0 < nHigh) sort(rgo, nLow0, nHigh); if(nLow < nHigh0) sort(rgo, nLow, nHigh0); Implementierung in Haskell: quicksort :: Ord a => [a] -> [a] quicksort [] = [] quicksort (pivot:xs) = quicksort [y | y <- xs, y<=pivot] ++ [pivot] ++ quicksort [y | y <- xs, y>pivot] Kurz anmalen, wie der Quicksort funktioniert, als Schaubild: | x------| | = [a]  Elemente <x und Elemente >x [y| y <-xs, y<pivot] =| | ++[pivot]++ | | =[y| y <-xs, y>pivot] Quicksort rekursiv auf Teillisten anwenden Rekursionsanker: leere Listen sind schon geordnet dann noch aneinanderketten der Listen (vgl. PI3,S11)

9 Jahreszahl Theorie / Sprache Entwickler 1932 l-Kalkül (siehe weiter hinten) Ursprung und gemeinsamer Kern aller funktionalen Sprachen. Churchs Intention bei der Entwicklung des l-Kalküls war eine „Formalisierung des Berechenbarkeitsbegriffs auf der Basis von Funktionen“  „Churchsche These“. Diese These wurde durch die äquivalente Turing-Berechenbarkeit untermauert. Church, Kleene 1960 LISP (List Prozessing) Lisp war die erste funktionale Sprache, die von den Prinzipien der damaligen durch Fortran geprägten Programmierung abwich. Wesentliche Neuheiten von LISP waren: bedingte Ausdrücke, Verwendung von Listen als Basisstruktur, Heapverwaltung mit Garbage Collection John McCarthy 1975 ML (Meta Language) Das Bedeutendste in ML ist das mächtige polymorphe Typenkonzept, das von den meisten modernen funktionalen Sprachen adaptiert wurde. (vgl Abschnitt Typen) Milner, Gordon, University of Edinburgh 1980 Hope In Hope wurden zum ersten Mal benutzerdefinierte Datenstrukturen und Pattern Matching bei der Definition von Funktionen über solchen Strukturen zugelassen. R. Burstall, D. MacQueen, D. Sannella, Uni. of Edinburgh

10 D. Turner, University of Kent
Jahreszahl Theorie / Sprache Entwickler 1985 Miranda Eine der wenigen kommerziell vertriebenen funktionalen Sprachen. Besonders ist hier der Einsatz von Funktionalen (Funktionen höherer Ordnung), sowie die bedarfsgesteuerte Auswertungsstrategie „lazy evaluation“ D. Turner, University of Kent ~1988 Haskell ( Vorname des Logikers Haskell Brooks Curry ) Haskell ist nach dem amerikanischen Logiker Haskell Brooks Curry benannt (weil Haskell [die Sprache] curryfizierte Funktionen liebt, wie Haskell [der Logiker] Haskell wurde von einem Komitee von Forschern entwickelt, die das Ziel verfolgten eine rein funktionale Programmiersprache einzuführen. Haskell unterstützt eine enrome Vielfalt von (auch oben aufgeführten) Konzepten und zeichnet sich insbesondere durch ein mächtiges Typsystem und eine saubere Modellierung von interaktiven Ein-/Ausgaben aus. Bemerkenswert ist, dass eine vollständige formale Semantikdefinition ( existiert. Ziele beim Entwurf von Haskell waren: Für Lehre, Forschung und Anwendungen, insbesondere für Programmierung großer Systeme Vollständige Beschreibung von Syntax und Semantik Frei erhältlich Basiert auf allgemein akzeptierten Ideen Komitee unter Leitung von P.Hudak (Yale University), Ph. Wadler (Glasgow University) Logiker H. B. Curry Curry ~ zusammenfassen, Tupel bilden, … curry :: ((a,b) -> c) -> a -> b -> c

11 Entwicklung Zur Geschichte: 1988 Gründung des Haskell-Komitees (auf der FPCA), dem u.a. Paul Hudak, Simon Peyton Jones und Philip Wadler angehören. 1990 Haskell 1.0 Sprachdefinition 1992 Haskell 1.2 Sprachdefinition 1996 Haskell 1.3 Sprachdefinition 1997 Haskell 1.4 Sprachdefinition 1999 Haskell 98 Sprachdefinition

12 l - Das Lambda-Kalkül Das Lambda-Kalkül besteht aus zwei Bausteinen
Funktionsabstraktion lx.A definiert eine (anonyme) Funktion, die ein x bekommt, und einen Ausdruck A als Funktionskörper hat (in dem in der Regel x vorkommt, aber nicht vorkommen muß) Funktionsapplikation FA bedeutet, daß die Funktion F auf dem Ausdruck A angewandt wird Die Groß- u. Kleinschreibung dient nur der Übersicht, es gibt keinen Grund Funktionen und Variablen zu unterscheiden, denn es kommt auf den Kontext an.

13 Beispiele für Funktionen (1)
Die Identität: lx.x Eine Funktion, die jedes Argument auf die Identitätsfunktion abbildet: ly.(lx.x) Die Identität, angewandt auf sich selbst: (lx.x)(ly.y)  (ly.y)

14 Beispiele für Funktionen (2)
Nicht alle Variablennamen müssen definiert sein, auch die folgenden sind korrekte l-Terme lx.Fx (ly.y)(z)  ? uv lk.Jm

15 Beispiele für Funktionen (3)
Ein komplexerer Ausdruck (lf.(lx.f(fx)))uv (lx.u(ux))v u(uv) (lf.(lx.f(fx)))uv vorher vortragen!!!! Frage: Was macht diese Funktion? Diese Funktion wendet also eine Funktion zweimal auf ein Argument an.

16 Eigenschaften des l-Kalküls
Als Bausteine gibt es nur Funktionsabstraktionen und -applikationen. Das ist alles! Es gibt keine Zahlen, Funktionsnamen, arithmetische Funktionen, Wahrheitswerte Die Funktionen werden nicht benannt, sie sind anonym. (Alle heißen l) Das Lambda-Kalkül ist ungetypt

17 Kalkül Definition Ein Kalkül besteht aus zwei wesentlichen Teilen:
Der Kalkülsprache, d.h. einem zugrunde liegenden Alphabet von Zeichen einer Definition der wohlgeformten Ausdrücke Dem Deduktionsgerüst, d.h. Axiomen aus der Menge der wohlgeformten Ausdrücke (Terme) Ableitungsregeln, mit denen Ausdrücke umgeformt/ausgewertet werden nach K.Schröter(1941) Diese Seite soll hauptsächlich der Erklärung des Namens Lambda-Kalkül dienen. Deshalb auch keine Definition von Alphabet, Zeichen, Ausdruck, …

18 kurzer weiterer Ausblick
Auf den ersten Blick bietet das l-Kalkül nur sehr primitive Funktionen, die nicht von praktischem Nutzen sind. Man kann allerdings mit dem l-Kalkül Fallunterscheidungen, Zahlen und arithmetische Funktionen herleiten

19 kurz notiert(1) Um Zahlen zu erhalten, werden wir jetzt ganz bestimmte Funktionen mit den natürlichen Zahlen identifizieren: FnA (n-malige Anwendung von F auf A) entspricht der induktiven Definition F0A:=A Fn+1A:= F(FnA) Die Zahlen z0,z1,… werden dann definiert durch: zn:=lfx.fn(x) Frage: Was entspricht der 3? l fx.f(f(f(x))) Frage: Was entspricht der 0? l fx.x Was entspricht der 42?

20 lzz‘fx.zf(z‘fx) kurz notiert(2)
Definition von Plus: für zwei Zahlen z und z‘ lzz‘fx.zf(z‘fx) Definition von Mal lzz‘fx.z(z‘f)x Beispiel Z2 und z3 z2=(lfx.f(f(x))) z3=(lfx.f(f(f(x)))) Plus: (zz‘fx.zf(z‘fx)) Z2 z3 z‘fx.z2 f(z‘fx)) z3 z‘fx.f(f(z‘fx))) z3 fx.f(f(f(f(f(x))))) = z5 Eine Beispielrechnung für die Multiplikation sei als Übungsaufgabe dem geneigten Studenten überlassen 

21 Beispiel zur Addition (verkürzt)
Beispiel: Plus z2 z3  z5 z2=(λ f x . f (f (x))) z3 = (λ f x . f (f (f (x)))) Plus z2 z3 (λ z z’ f x . z f (z’ f x)) z2 z3 → (λ z’ f x . z2 f (z’ f x)) z3 → (λ z’ f x . f ( f (z’ f x))) z3 → (λ f x . f ( f (z3 f x))) → (λ f x . f ( f ( f ( f ( f (x)))))) ( = z5 )

22 Beispiel zur Addition (ausgeschrieben)
Am Beispiel: Plus z2 z3 (→ z5 ) Plus z2 z3 (λ z z’ f x . z f (z’ f x)) (λ g y . g (g (y))) (λ g y . g ( g ( g (y)))) → (λ z’ f x . (λ g y . g (g (y))) f (z’ f x)) (λ g y . g ( g ( g (y)))) → (λ z’ f x . (λ y . f ( f (y)) (z’ f x)) (λ g y . g ( g ( g (y)))) → (λ z’ f x . f ( f (z’ f x))) (λ g y . g ( g ( g (y)))) → (λ z’ f x . f ( f (λ g y . g ( g ( g (y))) f x))) → (λ f x . f ( f (λ y . f ( f ( f (y))) x))) → (λ f x . f ( f ( f ( f ( f (x)))))) ( = z5 )

23 kurz notiert(3) Es ist außerdem möglich If-Anweisungen mit dem l-Kalkül auszudrücken. Sei True := lxy.x (Projektion auf das erste Argument) Sei False := lxy.y (Projektion auf das zweite Argument) Damit können wir ein If definieren: If .. then .. else .. entspricht hier: lbxy.bxy wobei b entweder True oder False ist.

24 Resultat aus der Theoretischen Informatik
Das l-Kalkül ist logisch äquivalent zu der Turing-Maschine. Somit kann man mit dem l-Kalkül (zumindest theoretisch) genau die Probleme lösen (ausrechnen), die die heutigen Computer auch lösen können. Jede von einem Computer berechenbare Funktion ist auch im Lambda-Kalkül berechenbar.

25 Evolution der Programmiersprachen
Problemspezifikation Programm Rechner „high level“ PS Assembler Maschinensprache vertical migration

26

27 Grundkonzepte funktionaler Sprachen, insb. Haskell
Die meisten Anwendungsprobleme sind auf natürliche Weise als Funktionen definiert, Bsp.: sin x, exp, … LATEX: Datenbanksysteme (SQL): EVA-Prinzip f1 Eingaben Ausgabe fn Funktion

28 Grundkonzept Haskell Auch Haskell arbeitet so:
Ein funktionales Programm ist eine Menge von Funktionsdefinitionen f1 X1 .. Xn = e1 fr X1,r .. Xn,r = er Funktionsbezeichner Parametervariablen Rumpfausdruck Eine Funktion transformiert Eingabe in Ausgabe Ein besonderer Vorteil dieses Konzepts ist die Tatsache, dass es keine Seiteneffekte geben kann. Dadurch, dass es keine globalen Variablen gibt, werden Funktionen nur durch ihre Funktionsparameter bestimmt und die Ausgabe ist somit zu jedem beliebigen Zeitpunkt des Programmablaufs identisch. Dies erhöht die Übersicht enorm. Theoretisch kann man jede Programmiersprache so benutzen, dass sie zu einer rein funktionalen Sprache wird. Allerdings ist die Ausführung dann nicht besonders effektiv.

29 Beispiele in Haskell -- hier stehen Kommentare
-- einfache arithmetische Funktionen add x1 x2 = x1 + x2 square x = x * x negate x = -x -- Konstantendefinitionen e = newline = '\n' -- Test auf Identität: Vergleichoperatoren allEqual n m p = (n==m) && (m==p) -- Maximumsfunktion: Bsp. für Fallunterscheidung max a b | a>b = a | a==b = a | otherwise = b Bei Konstanten handelt es sich trotzdem um Funktionen, allerdings mit 0 Parametern.

30 Typen In Haskell haben alle Datenobjekte einen wohldefinierten Typ.
Ein Typ ist eine Menge von Objekten gleicher Art, z.B. existieren Basistypen wie Int = Menge aller ganzen Zahlen (32 Bit) Integer = Menge beliebiger ganzer Zahlen, insb. nur durch den Speicher beschränkte große Zahlen Bool = {True, False} Char = Menge aller Zeichen String = Eine Liste von Char Neben diesen Basistypen gibt es auch Funktionstypen, wie z.B.: Int  Int = Menge aller einstelligen Funktionen über den ganzen Zahlen (wie z.B.: Quadrieren): Int  Int  Int = Menge aller zweistelligen Funktionen über den ganzen Zahlen (wie z.B.: Addieren): In Haskell- Programmen können optional Typdeklarationen der Form name :: type zu Definitionen angegeben werden. Bei der Compilation von Programmen erfolgt eine automatische Typinferenz und Typüberprüfung (type checker). Nur korrekt typisierbare Programme können somit compiliert werden. Hierdurch werden viele Programmfehler frühzeitig erkannt. Ist keine konkrete Typisierung vorgenommen, so bestimmt der Compiler automatisch den allgemeinsten Typ für jedes Datenobjekt. Beispiele einblenden

31 Beispiele in Haskell -- hier stehen Kommentare
-- einfache arithmetische Funktionen add :: Int -> Int -> Int add x1 x2 = x1 + x2 square :: Int -> Int square x = x * x negate :: Int -> Int negate x = -x -- Konstantendefinitionen e :: Double e = newline :: Char newline = '\n' -- Test auf Identität allEqual :: Int -> Int -> Int -> Bool allEqual n m p = (n==m) && (m==p) -- Maximumsfunktion? Fallunterscheidung max :: Double -> Double -> Double max a b | a>b = a | a==b = a -- bedingte Auswertungen, funktioniert wie | otherwise = b -- eine if/case-Struktur, das erste passende wird -- ausgewertet. Otherwise ist also im Grunde nichts anderes als die Konstante True. Hier kann ich nochmals auf die Klammern eingehen, insbesondere auf den Unterschied zwischen add :: Int -> Int -> Int add x1 x2 = x1 + x2

32 Typen Bei der Compilation von Programmen erfolgt eine automatische Typinferenz und Typüberprüfung (type checker). Nicht typisierte Programme werden automatisch möglichst allgemein typisiert. Ist ein Programm im Hugs-System geladen, kann man mit :t <Funktionsbezeichnung> die Typdeklaration eines Objekts erfahren. z.B.: Möglichkeiten, kann der sich Irren

33 Beispielprogramm Kryptographie (1)
Als Beispielprogramm betrachten wir das Caesar-Verschlüsselungsverfahren. Hierzu stellt man sich das Alphabet (im einfachen Fall nur die kleinen Buchstaben) im Kreis angeordnet vor. Ordnet man den Zeichen von a bis z die Nummern 0 bis 25 zu, so ist das Verschieben innerhalb des Kreises eine Addition modulo 26. Die Verschlüsselung besteht darin, anstelle jedes Klartextbuchstabens das Zeichen auszugeben, das im Kreis um eine festgelegte Anzahl von Positionen später kommt. Veranschaulichung

34 Beispielprogramm Kryptographie (2)
Somit ergibt sich die Funktion schiebe: Als nächstes müssen wir zwei Übergangsfunktionen zwischen den Zahlen und den Zeichen definieren schiebe :: Int -> Int -> Int schiebe schluessel zahl = mod (zahl + schluessel) 26 Hier kann ich die Studenten versuchen lassen, den Sinn von schiebe und die Typdefiniton zu erklären. Als nächstes soll man ein Beispiel rechnen. Jetzt sollen die Studenten selber die Funktion position (die einem Zeichen eine Zahl) und die Funktion buchstabe (die einer Zahl ein Buchstaben) zuordnet programmieren (Tafel, jemand oder ich) dazu gibt es folgende 2 Funktionen: ord :: Char -> Int chr :: Int -> Char position :: Char -> Int position zeichen = (ord zeichen) - 97 buchstabe :: Int -> Char buchstabe zahl = chr (zahl + 97)

35 Beispielprogramm Kryptographie (3)
Als nächstes definieren wir eine Funktion caesar:: Int -> Char -> Char die mit einem Schlüssel ein Zeichen verschlüsselt. Dazu verwenden wir die vorigen Funktionen. caesar :: Int -> Char -> Char caesar schluessel zeichen = buchstabe (schiebe schluessel (position zeichen))

36 Beispielprogramm Kryptographie (4)
Die Verschlüsselung eines ganzen Wortes erfordert die zeichenweise Anwendung dieser Funktion auf die Buchstaben des Wortes. Hierzu lässt sich die Funktion map verwenden, mit der eine Funktion elementweise auf eine Zeichenkette angewendet werden kann. Eckige Klammern um den Typ Char signalisieren, dass es sich um eine Liste von Char handelt (also um einen String). caesar_wort :: Int -> [Char] -> [Char] caesar_wort schluessel wort = map (caesar schluessel) wort Bemerkenswert ist hier die Tatsache das caesar schluessel als eine einstellige Funktion betrachtet wird (Da der Erste von den beiden Parametervariablen bereits fest dasteht).

37 Beispielprogramm Kryptographie (5)

38 Auswertung Bei der Auswertung von Ausdrücken werden die Funktionsdefinitionen als Ersetzungsregeln interpretiert. In einem Reduktionsschritt wird eine Funktionsapplikation durch den Rumpf der entsprechenden Funktionsdefinitionen ersetzt. Dabei wird eine Substitution der Parameter vorgenommen. Ein Ausdruck ohne reduzierbare Teilausdrücke heißt Normalform. Die Normalform eines Ausdrucks ist somit das Resultat seiner Auswertung. verschiedene Auswertungsstrategien (left-most-outer-most)(Left-most-inner-most)(lazy evaluation) Hier rechne ich an der Tafel ein Beispiel: allEqual (3*(9- (negate 5))) 42 (square 6) ==> allEqual (3*(9- (-5))) 42 (6*6) allEqual (3*(14))) 42 (36) ------ allEqual (42) 42 (36) (42==42) && (42==36) True && False False

39 Verschiedene Auswertungsstrategien
Haskell verwendet eine Form der Left-most outermost Strategie Auf dieser Strategie baut die bedarfsgesteuerte Auswertungsstrategie auf (engl. lazy evaluation, call by need) Das Motto von Lazy Evaluation lautet: Leftmost outermost: Unter den am weitesten außen befindlichen Redexen, also reduzierbaren Teilausdrücken, die nicht Teilausdruck eines anderen Redexes sind, wird der am weitesten links stehende ausgewertet. Beispiel: inf x = inf x –-inf definiert die nirgendwo definierte Funktion const_fct y = 42 -konstante Funktion Wertet man in dem Ausdruck (const_fct (inf 0)) zunächst den inneren Redex (inf 0) aus, terminiert die Berechnung nicht. Wertet man zuerst den äußeren Redex aus, so erhält man sofort das Ergebnis 42 Nachteil der leftmost outermost-Strategie ist allerdings, dass eine effiziente Implementierung dieser Strategie schwieriger ist, da nun Funktionen mit unausgewerteten Argumentausdrücken aufgerufen werden können und somit beliebig unausgewertete Ausdrücke als „Daten“ verwaltet werden müssen. Berechne einen Ausdruck bzw. einen Teilausdruck nur, wenn es unbedingt nötig ist und dann auch nur einmal.

40 Rekursive Funktionen Rekursion ist eine selbst-referenzierende Art der Definition. Von Rekursion spricht man, wenn in der Definition einer Funktion auf die Funktion selbst Bezug genommen wird. Grundidee: Meistens „Divide and Conquer“ Prinzip Wir zerlegen das Problem in zwei Fälle: Einen leichten Fall, den wir lösen Und einen schweren Fall, den wir auf das leichte Problem zurückführen

41 Beispiele zur Rekursion
Rekursion kommt häufig in der Mathematik und in der Informatik vor, z.B.: Die Fakultätsfunktion: n! Fibonacci-Zahlen: fib0=0 fib1=1 fibn=fibn-1+fibn-2 Übung: Programmieren Sie diese beiden Funktionen mit ihrem Tischnachbarn auf Papier und werten Sie einen nichttrivialen Beispielausdruck dazu aus. Abbruch-Bedingung immer über Bedingte Anweisung Wie sieht das hier bei dem Lambda-Kalkül aus, ist das da auch möglich? Es ist so (rekursiv) nicht möglich, da die Funktionen dort Anonyme Funktionen sind, keinen Namen haben. Gibt man den Funktionen namen, so wäre es möglich. Formuliert man das zu einer iterativen Formel, ist es möglich. Jede Rekursive Funktion lässt sich iterativ umschreiben

42 weiterführende Beispiele für Rekursion in Haskell
Durch das Grundprinzip der deklarativen Sprachen in Kombination mit der Rekursion lassen sich somit leicht mathematische Strukturen auf den Computer übertragen. Als Beispiel kann man einen Baum nennen. Dieser lässt sich in Haskell rel. einfach als neue Datenstruktur anlegen und man kann sehr einfach auf ihm operieren. Einfache Beispiele sind z.B. folgende Geometrische Formen

43 Beispiele Zum Beispiel kann man Zettel 6 laden und zeigen, wie sich das Bild erstellt Der Vorteil von dem Grafikmodul ist, dass man schnell sieht, wenn man sich verprogrammiert hat und sogar relativ schnell nachvollziehen kann, wo der Fehler war. Das ist gut für Schüler, die Rekursion lernen sollen. Hugs verfügt auch über eine grafische Ausgabe. Mit ihr kann man relativ leicht solche Strukturen erzeugen.

44 Etwas komplexere fraktale Strukturen
Mit etwas mehr Rechen-power und Mathematik ist es dann auch möglich beliebige komplexe Strukturen zu erzeugen. Weiteres Material (Tutorials, Papers, …) sowie den Compiler findet man unter © by Christian Heil


Herunterladen ppt "Eine rein funktionale Sprache"

Ähnliche Präsentationen


Google-Anzeigen