Vorlesung: Praxis der Funktionalen Programmierung | Index

Was soll der Sequencer können?

Mit unserem Sequencer wollen wir Midiströme auf intelligente Weise erzeugen und abspielen. Besonderheiten sollen dabei erstens eine möglichst fortschrittliche Beschreibungssprache und zweitens eine grafische Oberfläche sein, über die man Parameter der Programme, und sogar Programmteile selbst, während der Ausführung noch ändern kann. Erst so etwas dürfte das System auch clubtauglich machen, ansonsten könnte man zwar tolle Musik spezifizieren, aber diese wäre dann vorkompiliert und nur noch unverändert abspielbar. Dann kann man auch gleich eine Schallplatte machen.

Im derzeitigen Zustand ist der Sequencer keineswegs komplett und fertig, ich beschreibe aber den Entwurf, und dann werden wir sehen, wie und wann es sich weiter entwickelt. (Die Programmierung ist unter anderm auch einfach eine Zeitfrage. Eine Version ohne GUI läuft bereits, daran kann man auch zeigen, was das GUI noch leisten sollte.)

Nun ist klar, daß das eine eher selten gebrauchte Anwendung ist, aber warum erzähle ich es hier? Es zeigt typische Schritte der Implementierung mittelkleiner Software-Projekte und wie wir dabei spezielle Eigenschaften funktionaler Sprachen nutzen können. Der Arbeitsgang ist folgender

Wenn wir "nur" bis hierher gehen, haben wir eine sogenannte eingebettete systemspezifische Sprache. Eingebettet, weil dann eben Haskell-Programme schreiben (die die Operatoren des Zielbereichs aufrufen). Wir haben dieses Verfahren bereits bei der Parserkonstruktion gesehen: der Parser sah aus wie eine Grammatik, war tatsächlich ein Haskell-Programm. (Es gibt auch bereits eine eingebettete Haskell-Musiksprache, nämlich Haskore TODO: link).

Was sind die Vorteile einer eingebetteten Sprache? Wir erben viele Eigenschaften der Gastsprache. Beispielsweise in Haskell die lokalen Bindungen, Funktionen höherer Ordnung, das Modul- und das Typsystem. Wir müssen uns da also erstens nichts neues ausdenken, zweitens nichts implementieren, und sind drittens sicher, daß und wie es funktioniert.

Hat das überhaupt Nachteile? Wir erben natürlich auch die Implementation (Laufzeitumgebung) der Gastsprache: haben wir einen Haskell-Compiler, wird es eben auch nur kompilierte Musik geben. Haben wir einen Interpreter, gibt es interpretierte Musik. In beiden Fällen jedoch gilt: wollen wir das Programm ändern, müssen wir sein Ausführung stoppen, dann neu kompilieren (oder hugs muß die Module neu laden), und dann neu die Ausführung beginnen. Das ist natürlich grade bei Musik nicht zu vertreten.

Das ist kein inhärenter Nachteil funktionaler Sprachen, die vorliegenden Haskell-Implementationen sind eben so. Unsere Rettung wäre die funktionale Sprache Erlang (TODO: link), die üblicherweise im ständig laufenden Betrieb eingesetzt wird (für Telekommunikations-Steuerung): das Laufzeitsystem ist so gebaut, daß es erstens über viele Rechenknoten verteil ist und zweitens daß "live", d. h. während der Programmausführung Module gewechselt werden können. Das erfordert einige Einschränkungen, aber es geht, und es geht sogar sehr gut (sagt Ericsson). Warum nehmen wir dann nicht Erlang? Es ist ja seit einiger Zeit sogar frei verfügbar. Nun, erstens war das für mich ein bißchen spät, und zweitens hat Erlang ein ganz anderes Typsystem (nämlich eher LISP-ähnlich: jedes Ding hat einen Typ, aber der ist erst zur Laufzeit sicher bekannt). Wenn ich also live Programme modifizieren will, dann muß ich zwangsläufig mir eine Programmiersprache definieren und einen Interpreter und eine Laufzeitumgebung schreiben.

Deswegen setzen wir die Liste der Arbeitsschritte fort:


best viewed with any browser


http://www.informatik.uni-leipzig.de/~joe/ mailto:joe@informatik.uni-leipzig.de