Alles ist eine Funktion: Rückblick auf David Beazleys SICP-Kurs
(ezzeriesa.notion.site)Rückblick auf David Beazley und den SICP-Kurs: Eine Woche Erfahrung
Hier werden die Erfahrungen mit David Beazleys SICP-Kurs Ende 2022 geteilt. Es gibt zwar viele kostenlose Materialien, aber Daves Kurs war besonders effektiv, weil er bestimmte Themen auswählte und sie tiefgehend erklärte.
Ausgangspunkt
Der SICP-Kurs wurde in der Sprache Scheme durchgeführt. Hier wurde zur Erklärung des grundlegenden Substitutionsmodells ein einfacher Scheme-Interpreter in Python implementiert.
Grundlagen der Sprache Scheme
- Primitive: Grundlegende Werte (z. B. Ganzzahlen)
- Operatoren: Grundoperationen wie
+,-,*,/werden in Präfixnotation verwendet - define: Variablendefinition
> (define x 2)
> (+ x 3) ; Ergebnis: 5
- if: Bedingungsausdruck
- lambda: Definition anonymer Funktionen
> ((lambda (x) (* x x)) 3) ; Ergebnis: 9
Scheme-Interpreter in Python
Mit Python wurde ein einfacher Interpreter implementiert, der Scheme-Code auswertet. Die Grundoperationen wurden als Python-Funktionen definiert.
definitions = {
"+": lambda x, y: x + y,
"*": lambda x, y: x * y,
}
Beispiel:
> evaluate(("+", 2, 3)) # Ergebnis: 5
Enthalten waren außerdem die Implementierung von define und lambda sowie die Verarbeitung des Bedingungsausdrucks if.
Substitutionsmodell
Das Substitutionsmodell ist eine einfache Art, Programme zu interpretieren: Variablen werden beim Auswerten durch Werte ersetzt. Sobald jedoch Zuweisung (assignment) hinzukommt, funktioniert dieses Modell nicht mehr.
Zustand
Ein Beispiel dafür, wie das Substitutionsmodell zusammenbricht, ist Zuweisung (assignment). Wenn man etwa den Kontostand eines Bankkontos modelliert, wird mit set! eine Variable aktualisiert.
(define balance 100)
(define (withdraw amount)
(set! balance (- balance amount))
balance)
In diesem Fall kann das Substitutionsmodell den Kontostand vor und nach der Änderung nicht unterscheiden.
Daher wird ein Umgebungsmodell (Environment) benötigt. Variablen werden innerhalb einer Umgebung definiert, und jede Prozedur besitzt ihre eigene Umgebung.
Streams
Eine weitere Möglichkeit, Zustand zu modellieren, sind Streams. Mit lazy evaluation können Streams auch zukünftige Werte modellieren.
Endlosschleifen und Auswertungsreihenfolge
Unterschiede in der Auswertungsreihenfolge: Die meisten Sprachen verwenden applicative-order evaluation und werten zuerst die Argumente aus.
> (square (+ 1 2)) ; Ergebnis: 9
Bei normal-order evaluation wird die Auswertung der Argumente jedoch verzögert, bis sie tatsächlich benötigt werden. Dadurch lassen sich Endlosschleifen vermeiden.
> (define (p) (p))
> (define (test x y) (if (= x 0) 0 y))
> (test 0 (p)) ; Bei normal-order wird 0 zurückgegeben, bei applicative-order entsteht eine Endlosschleife
Lambda-Kalkül und Church-Zahlen
Mit Church-Encoding lassen sich Zahlen als Prozeduren darstellen. Das ist ein wichtiges Konzept der funktionalen Programmierung.
(define (zero f) (lambda (x) x))
(define (increment n) (lambda (f) (lambda (x) (f ((n f) x)))))
zeroist eine Funktion, die ihr Argument unverändert zurückgibt (dieidentity-Funktion).incrementwendet einen Funktionsaufruf einmal zusätzlich an.
Beispiel
> ((zero (lambda (x) (+ x 1))) 0) ; Ergebnis: 0
> (((increment zero) (lambda (x) (+ x 1))) 0) ; Ergebnis: 1
Iteration vs. Rekursion
Scheme verwendet statt einer for-Schleife Rekursion, um wiederholte Aufgaben auszuführen.
Rekursionsbeispiel: Fakultät
(define (factorial n)
(if (= n 1)
1
(* n (factorial (- n 1)))))
Dieser rekursive Aufruf kann durch die Nutzung des Stacks viel Speicher verbrauchen.
Tail-Call-Optimierung
Scheme reduziert den Speicherverbrauch durch Tail-Call-Optimierung. Dadurch verhält sich der Ablauf wie ein iterativer Prozess.
(define (factorial n)
(define (iter product counter)
(if (> counter n)
product
(iter (* product counter) (+ counter 1))))
(iter 1 1))
Abschluss
David Beazleys Kurs behandelt ausgewählte Kernkonzepte aus SICP in großer Tiefe. Besonders hilfreich war er dabei, verschiedene Programmierparadigmen wie funktionale Programmierung, Lambda-Kalkül und Auswertungsreihenfolgen zu verstehen.
Zitat von Knuth
Wenn man nur Theorie studiert, bedeutet das, dass es Zeit ist, sich auf die praktische Seite zu konzentrieren; und wenn man nur praktisch arbeitet, bedeutet das, dass es Zeit ist, sich auf die theoretische Seite zu konzentrieren.
1 Kommentare
Hacker-News-Kommentare
Die SICP-Vorlesungen haben eine hohe Informationsdichte, benötigen aber durch die Fragen und Antworten der Studierenden sowie die Nutzung der Tafel viel Zeit. Auch die Reihenfolge der Vorlesungen ließe sich möglicherweise neu strukturieren. Ich plane persönlich eine neue Videoserie.
Es wird vorgestellt, wie sich Zustand als reine Funktion kodieren lässt. Es gibt verschiedene rein funktionale Kodierungen für unterschiedliche Daten.
Durch den URL-Anker/Hash des Blogposts landete ich direkt beim Postskriptum, was verwirrend war.
Die Implementierung von cons/car/cdr mit Lambdas wirkte beim ersten Mal wie Magie. Das zeigt, dass die Sprachlaufzeit ein Schlüssel/Wert-Wörterbuch implementieren muss.
David Beazley ist eine legendäre Figur in der Python-Welt, und diese Vorlesung war zunächst überraschend, erschien dann aber schnell als perfekte Kombination. Ich habe mich für die nächste Vorlesung angemeldet.
Ich bin auf das Konzept gestoßen, dass induktive Datentypen notwendig sind. Allein mit Church-Kodierung lassen sich keine Aussagen wie
0 != 1beweisen.Der Artikel selbst war interessant, aber die Navigation auf der Seite war schwierig. Mit den Pfeiltasten der Tastatur ließ sich nicht scrollen.
Im Code im Abschnitt „Alternatives Modell“ gibt es einen Tippfehler. Statt
fibsolltefibonacciverwendet werden. Der Code im GitHub-Repository ist korrekt.Es gibt einen Link zu einer laufenden Diskussion über das Buch. Ich frage mich, warum der Link direkt zur Diskussion am Seitenende führt und ob das in eine andere Diskussion integriert werden könnte.
Ein YouTube-Link wurde bereitgestellt