Diese Masterarbeit wird sich mit dem jungen und modernen Lisp-Dialekt Clojure und seinen Sprachfeatures beschäftigen. Clojure läuft innerhalb der Java Virtuel Machine (JVM) und kann somit nahtlos in objektorientierte Java-Programme integriert werden, um beispielsweise nebenläufige Algorithmen umzusetzen. Daneben existieren alternativ auch eine CLR- sowie JavaScript-Implementierung.
Im Rahmen dieser Arbeit wird neben den Concurrency-Features auch die Technologie Software Transactional Memory (STM) vorgestellt, mit dessen Hilfe sich die ACID-Eigenschaften auf den zu manipulierenden transienten Speicher abbilden lassen. Eine Transaktion bündelt Befehle, die auf gemeinsame Ressourcen zugreifen. Falls zwei Transaktionen auf die gleiche Ressource zugreifen möchten, wird eine der beiden Transaktionen abgebrochen. Die Sprache bietet hierfür die benötigten
Konstrukte. Ein wichtiges Pattern innerhalb der Objektorientierten Programmierung ist die Trennung der Programmierschnittstelle von der Implementierung, realisiert durch Sprachelemente wie Interfaces und Klassen sowie Vererbung und Polymorphie. Clojure kann als funktionale Sprache diesen traditionellen Lösungsansatz nicht verwenden und führt Alternativen ein. Die Sprachelemente Protocols, Multimethods und Datatypes werden hierzu näher beschrieben.
Neben den Clojure-spezifischen Sprachfeatures werden weitere grundlegende Prinzipien und Entwurfsmuster der Funktionalen Programmierung wie z.B. Macros, Lambdas, Currying, Memoization, Closures und Monaden vorgestellt. Um Clojure von anderen funktionalen Sprachen abgrenzen zu können, werden abschließend Alternativen vorgestellt und ein Vergleich bezüglich Funktionsumfang und Performance mit Haskell durchgeführt.
Inhaltsverzeichnis
1 Einleitung
1.1 Motivation
1.2 Zielstellung
2 Grundlagen der Funktionalen Programmierung
2.1 Eigenschaften Funktionaler Programmierung
2.1.1 Werte und veränderliche Objekte
2.1.2 First-Class, High-Order und Reine Funktionen
2.1.3 Collections und Datentypen
2.2 Programmierparadigmen
2.2.1 Imperative und Prozedurale Programmierung
2.2.2 Objektorientierte Programmierung
2.2.3 Deklarative Programmierung
2.2.4 Weitere Programmierparadigmen
2.3 Funktionale Idiome
2.3.1 Lambda und Anonyme Funktionen
2.3.2 Closures
2.3.3 Currying
2.3.4 Memoization
2.4 Zusammenfassung
3 Clojure-spezifische Sprachmerkmale
3.1 Makros
3.1.1 Makros in anderen Sprachen
3.1.2 Makros in Clojure
3.1.3 Quote und Syntax-Quote
3.1.4 Hygiene
3.2 Datentypen und Protokolle
3.2.1 Definition von Protokollen
3.2.2 Erweitern von Datentypen
3.2.3 Benutzerdefinierte Typen
3.2.3.1 defrecord
3.2.3.2 deftype
3.2.3.3 Inline Implementierung von Protokollen
3.3 Multimethoden
3.3.1 Mutlimethoden Type-Dispatch
3.3.2 Hierarchien
3.4 Ausnahmebehandlung
3.5 Clean Code und Entwurfsmuster
3.5.1 Dependency Injection
3.5.2 Strategy Pattern
3.6 Zusammenfassung
4 Sprachfeatures zur nebenläufigen Programmierung
4.1 Grundlagen paralleler Programmierung
4.1.1 Multitasking und Multithreading
4.1.2 Schwierigkeiten der parallelen Programmierung
4.1.3 Klassische Lösung der Threading-Probleme
4.2 Zustand und Identität
4.3 Referenztypen
4.3.1 Referenztyp var
4.3.2 Referenztyp atom
4.3.3 Referenztyp ref und Software Transactional Memory
4.3.4 Referenztyp agent
4.4 Change Tracking und Validierung von Referenztypen
4.5 Futures
4.6 Zusammenfassung
5 Erweiterter Einsatz von Clojure
5.1 Monaden
5.1.1 Definition einer Monade
5.1.2 Gesetze der monadischen Operationen
5.1.3 Verwendung und Einsatz
5.1.4 Weitere Monadentypen
5.1.4.1 Zustands-Monade
5.1.4.2 Maybe-Monade
5.2 core.logic
5.2.1 Einführung in die Logische Programmierung
5.2.2 Grundlagen von core.logic
5.2.2.1 Inferenzumgebung run
5.2.2.2 Relationen vs. Funktionen
5.2.2.3 Fakten und Regeln
5.2.2.4 Logische Variablen
5.2.2.5 conde und Pattern Matching
5.2.3 Anwendung
5.2.3.1 Anwendungsfälle
5.2.3.2 Praktisches Beispiel
5.2.3.3 Logisches Puzzle
5.3 Zusammenfassung
6 Alternative Funktionale Sprachen
6.1 Vorstellung alternativer Sprachen
6.1.1 Objective Caml
6.1.1.1 Das Typsystem
6.1.1.2 Funktionen
6.1.1.3 Pattern Matching
6.1.1.4 Rekursion
6.1.1.5 Weiteres
6.1.2 F#
6.1.2.1 F# vs. OCaml
6.1.2.2 Weiteres
6.1.3 Erlang
6.1.3.1 Multithreading-Support
6.1.3.2 Das Typsystem
6.1.3.3 Pattern Matching
6.1.3.4 Funktionen
6.1.3.5 Weiteres
6.2 Clojure im Vergleich mit Haskell
6.2.1 Funktionsumfang
6.2.2 Sprachfeatures
6.2.3 Performance
6.3 Zusammenfassung
7 Schlussfolgerung und Ausblick
Zielsetzung & Themen
Diese Masterarbeit analysiert den modernen Lisp-Dialekt Clojure und untersucht dessen Sprachfeatures sowie deren Anwendung, insbesondere im Bereich der nebenläufigen Programmierung. Die Arbeit erörtert, wie Clojure die Prinzipien der funktionalen Programmierung mit modernen Laufzeitumgebungen wie der JVM verbindet und traditionelle objektorientierte Lösungsansätze durch funktionale Alternativen ergänzt.
- Grundlagen und Paradigmen der funktionalen Programmierung
- Clojure-spezifische Sprachmerkmale wie Makros, Protokolle und Multimethoden
- Nebenläufigkeit und Concurrency-Features inklusive Software Transactional Memory (STM)
- Erweiterte Konzepte wie Monaden und die Bibliothek core.logic
- Vergleichende Analyse mit anderen funktionalen Sprachen wie Haskell, OCaml, F# und Erlang
Auszug aus dem Buch
3.1 Makros
Clojure besitzt nur wenige eingebaute Operatoren, welche als Special Forms bezeichnet werden. Die gesamte weitere Funktionalität wird durch Funktionen und Makros gebildet. Mit Hilfe von Makros ist der Entwickler in der Lage den Clojure Compiler zu kontrollieren und somit neue Operationen zu implementieren, welche nicht im Sprachumfang enthalten sind. Makros generieren Quellcode, welcher anschließend vom Clojure Compiler evaluiert und ausgeführt wird.
Im Gegensatz zu einem Funktionsaufruf werden bei einem Makro die übergebenen Argumente nicht evaluiert. Das Makro num-less-than-five aus Listing 3.4 erhält somit num als Symbol und nicht den Wert, den es benennt. Als Rückgabewert muss ein Makro ausführbaren Code generieren (also Listen), welcher anschließend durch den Clojure Compiler evaluiert wird. Die Symbole, welche nicht innerhalb des Makro evaluiert werden sollen, müssen gequotet werden (’). Diese Symbole werden somit erst durch den Clojure Compiler evaluiert, wenn das Makro expandiert wurde und das Ergebnis vorliegt. Mit Hilfe von macroexpand bzw. macroexpand-1 ist dies möglich. Ein expandiertes Makro kann weitere Makros enthalten, welche von Clojure rekursiv expandiert werden, bis der erzeugte Code keine weiteren Makros mehr enthält. Bei Verwendung von macroexpand-1 erfolgt die Expandierung nur einmal, bei macroexpand hingegen rekursiv. Beide dienen dem Debugging und werden nicht in Produktivumgebungen verwendet.
Zusammenfassung der Kapitel
1 Einleitung: Motivation für funktionale Programmierung und Zielsetzung der Arbeit bezüglich der Analyse von Clojure-Sprachfeatures.
2 Grundlagen der Funktionalen Programmierung: Erläuterung der Kernkonzepte wie Unveränderlichkeit, First-Class Funktionen und verschiedener Programmierparadigmen.
3 Clojure-spezifische Sprachmerkmale: Detaillierte Untersuchung von Makros, Protokollen, Multimethoden und Entwurfsmustern zur Erweiterung des Sprachumfangs.
4 Sprachfeatures zur nebenläufigen Programmierung: Einführung in parallele Programmierung und Vorstellung der Clojure-Referenztypen (var, atom, ref, agent) sowie STM zur sicheren Zustandsverwaltung.
5 Erweiterter Einsatz von Clojure: Vorstellung von Monaden als Entwurfsmuster sowie der Bibliothek core.logic zur Realisierung von Logikprogrammierung.
6 Alternative Funktionale Sprachen: Überblick über OCaml, F# und Erlang sowie ein ausführlicher Vergleich von Clojure mit Haskell.
7 Schlussfolgerung und Ausblick: Zusammenfassende Bewertung der Vorteile von Clojure und Einschätzung des Ökosystems für industrielle Projekte.
Schlüsselwörter
Clojure, Funktionale Programmierung, Lisp, Nebenläufigkeit, Concurrency, Software Transactional Memory, STM, Makros, Protokolle, Multimethoden, Monaden, core.logic, Polymorphismus, Referenztypen, Benchmark
Häufig gestellte Fragen
Worum geht es in dieser Arbeit grundsätzlich?
Die Arbeit beschäftigt sich mit Clojure, einem modernen Lisp-Dialekt auf der Java Virtual Machine, und untersucht, wie dessen spezifische Sprachmerkmale bei der Softwareentwicklung eingesetzt werden können.
Was sind die zentralen Themenfelder der Arbeit?
Die zentralen Themen sind funktionale Programmierung, Clojure-spezifische Features, Nebenläufigkeit (Concurrency) sowie die Erweiterung der Sprache durch Konzepte wie Monaden und Logikprogrammierung.
Was ist das primäre Ziel der Forschungsarbeit?
Das Ziel ist es, Clojure und seine Fähigkeiten, besonders im Bereich nebenläufiger Algorithmen und der Interoperabilität mit existierenden Systemen, fundiert zu bewerten und einzuordnen.
Welche wissenschaftliche Methode wird verwendet?
Die Arbeit nutzt eine analytische Literaturrecherche und empirische Code-Beispiele, um die Sprachfeatures zu demonstrieren und einen objektiven Vergleich mit anderen funktionalen Sprachen durchzuführen.
Was wird im Hauptteil der Arbeit behandelt?
Der Hauptteil gliedert sich in die theoretischen Grundlagen, die Analyse spezifischer Sprachmerkmale, die Implementierung von Concurrency-Lösungen sowie die Betrachtung alternativer funktionaler Sprachen.
Welche Schlüsselwörter charakterisieren die Arbeit am besten?
Schlüsselbegriffe sind Clojure, Funktionale Programmierung, Concurrency, STM, Protokolle, Makros, Monaden und core.logic.
Welche Rolle spielt die Software Transactional Memory (STM) in Clojure?
STM ist ein zentrales Feature zur sicheren Koordination von Speicherzugriffen in nebenläufigen Systemen, welches durch den Referenztyp 'ref' und das MVCC-Verfahren implementiert wird.
Wie unterscheidet sich Clojure in Bezug auf die Performance von Haskell?
Laut den betrachteten Benchmarks weist Clojure aufgrund der Einbettung in die JVM im Schnitt eine höhere Ausführungszeit und einen höheren Speicherverbrauch als Haskell auf.
- Quote paper
- Lutz Leonhardt (Author), 2013, Modernes Clojure. Einsatz und Bewertung moderner Sprachfeatures in Clojure, Munich, GRIN Verlag, https://www.grin.com/document/381390