[linux-l] Ocml vs. Java

Volker Grabsch vog at notjusthosting.com
Fr Sep 23 18:36:47 CEST 2005


On Thu, Sep 22, 2005 at 10:32:15PM +0200, Oliver Bandel wrote:
> > Doch, doch, genau wie in Python wird das auch in Ruby an den Stellen
> > eingesetzt, wo es sinnvoll ist. Aber die meisten funktionalen Konzepte
> 
> Ich meinte nicht, ob diese features eingesetzt werden, sondern
> ob Ruby selbst eingesetzt wird.
> IMHO nur sehr selten.

Ich habe was größeres damit gemacht. Ist wirklich nett, diese Sprache.
Von der Mächtigkeit her ist es mit Python vergleichbar, obwohl es doch
einige konzeptionelle Unterschiede gibt. Ich bin dann doch zu Python
gewechselt, weil diese Sprache nochmal "aufgeräumter" und syntaktisch
einfacher ist, weil eine keine "end"s mag :), und weil die Libraries
und Frameworks für Python schon viel weiter entwickelt sind. Außerdem
verleitet Ruby immer noch zu sehr zum "hacken". Da ist Python sauberer
designt, das wusste ich sehr zu schätzen. Aus demselben Grund hast du
übrigens auch mein Interesse für Ocaml geweckt: Ebenfalls kein Overhead
beim Programmieren und keine unnötige Komplexität ... abgesehen von
Interfaces wegen der Typen, aber du meintest, das zahlt sich auf jeden
Fall wieder aus. Da werde ich Python und Ocaml diesbezüglich mal
vergleichen.

> [...]
> > Und im Gegensatz zu funktionalen Sprachen funktioniert das auch
> 
> Was meinst Du hier mit Iteratoren?
> 
> Gib doch mal ein Beispiel.
> 
> Ohne beispiele kommen wir nicht weiter, weil wir sonst aneinander vorbei reden.
> Das haben wir bereits mehrfach getan.

RTFM:

	http://docs.python.org/tut/tut.html  (Python-Tutorial)

Kapitel "Listcomprehensions"
Kapitel "Iterators" ff.

Da ist alles kurz und bündig mit Beispielen erklärt.

Und bevor du mich damit nervst: Ja, Iteratoren kann man in einer
funktionalen Sprache auch als Funktion gestalten, die eine andere
Funktion entgegen nimmt und mehrmals mit gewissen Parametern aufruft.
Ja, natürlich! Aber in Python sind Iteratoren darüberhinaus noch Objekte
mit einer "next"-Methode. Dadurch vereinen Iteratoren in Python alle
positiven Eigenschaften, die man von Iteratoren in OO-Sprachen und von
Iteratoren in funktionalen Sprachen kennt.

Generator Expressions und Listcomprehensions sind weder sauberer noch
effizienter als ihre Pendants in einer funktionalen Sprache. Sie sind
IMHO einfach nur besser zu lesen, und schneller zu verstehen.

> > hervorragend mit Iteratoren, nicht nur mit Listen. Und darin liegt dann
> > nochmals eine enorme Stärke. Dass man mit Iteratoren fast genauso
> > leicht wie mit Listen arbeiten kann, dafür sorgen übrigens Iterator-
> > Generatoren, welche über Closures (d.h. einen "yield"-Ausdruck) verfügen
> > (auch sehr ähnlich zu Ruby, haben sie sich - glaubich - von Icon
> > abgeschaut).
> 
> Beipielcode + Beispielergebnis, bitte.

mach ich. Und ich nehme mal ein etwas anspruchsvolleres, einfaches
Beispiel, damit wir nicht nur Trivial-Lösungen miteinander vergleichen.
Siehe unten.

> > > Daß das ergebnis da oben schon steht liegt daran, daß ich das im Toplevel
> > > eingetippert habe.
> > > 
> > > List.iter2 (fun a b -> print_endline (string_of_int(a + b))) liste1 liste2
> > 
> > Also da fände ich eine Schleife aber sehr viel übersichtlicher. Hier
> > fängt man an, IMHO, die funktionalen Konzepte zu missbrauchen, um
> > schlecht lesbaren Code zu produzieren.
> 
> Nein.
> Die vielen Funktionen waren wegen unterschiedlicher Tyapen notwendig.
> (Keine casts!)

Wäre Python statisch typisiert, wären solche Konstrukte vielleicht auch
in Python nötig ... glaub ich aber nicht ... Listcomprehensions könnte
man in Ocaml sicher gut einbauen, sie würden sicher die Lesbarkeit
vieler Standard-Konstrukte erhöhen.

> Besser lesbar vielleicht so:
> 
> List.iter2 (fun a b -> Printf.printf "%d\n" (a + b)) liste1 liste2
> 
> Oder:
> 
> let my_sum_printer a b = Printf.printf "%d\n" (a + b)
> List.iter my_sum_printer liste1 liste2

Sicher, besser lesbar. Aber eben nicht so gut lesbar wie die
korrespondierende Python-Syntax. Um nichts anderes ging es.

> > Man fängt nämlich an, Funktionen zu verweden an Stellen, wo eigentlich
> > gar keine nötig sind.
> 
> Blödsinn.
> Du hast nicht verstanden, wie mächtig funktionale Programmierung ist
> und weil Du bei alt hergebrachtem bleiben magst (Schleifen),
> meinst Du das wäre schlechte Programmierung, es mit List.iter zu erledigen.
> Vielleicht wäre es besser, wenn Du bei OO bleibst und bei imperativem Code.
> Den Sinn funktionaler Programmierung scheinst Du nicht zu begreifen.

Das ist eine unhaltbare Beleidigung!

Ich bin kein unerfahrener Programmierer, dem du die funktionalen Konzepte
erst noch erklären musst. Du solltest mir nicht irgendwelche
Selbstverständlichkeiten erklären, als ob ich dich nicht verstanden
hätte, sondern einfach mal auf das eingehen, was ich *wirklich* sage.



Ich habe nie gesagt, dass List.iter unsauber sei, sondern nur, dass die
Python-Syntax (Listcomprehensions, Forschleifen) besser lesbar sind.
Konzeptioniell und von der Organisation des Codes her sind die
Unterschiede in diesem Punkt natürlich minimal.

Funktionale Konzepte sind mir sehr wohl vertraut ... *gerade* als
Python-Programmierer. In Python hat man all diese Konzepte beieinander:
Closures & funktionale Elemente auf der einen Seite, ein ausgefeites
dynamisches Typ- und Klassen-System auf der anderen Seite. In Python
kann man die verschiedenen Herangehensweisen wunderbar vergleichen
und gegenüberstellen.


Natürlich kann ich in Python sowas hier schreiben:

	def mein_iterator(f,start):
		f(start + 1)
		f(start * 2)
		f(start / 3)

	def innere_funktion(param):
		print param

	mein_iterator(innere_funktion,10)


liefert:

	11
	20
	3


Jetzt will ich aber den Iterator selbst noch parametrisieren, d.h. ich
will via "mein_iterator(10)" einen Iterator erzeugen können, den ich
erst später ablaufe. Auch das ist *natürlich* mit funktionaler
Herangehensweise möglich:


	def erstelle_iterator(start):

		def mein_iterator(f):
			f(start + 1)
			f(start * 2)
			f(start / 3)

		return mein_iterator

	# Iterator erstellen
	iter = erstelleiterator(10)

	# Iterator anwenden
	def innere_funktion(param):
		print param
	iter(innere_funktion)


Aber die Denkweise, dass der Iterator eine Funktion entgegennimmt, ist
IMHO eine Ecke zu viel, die man in Python abrunden kann. Genauso kann
man die Tatsache, dass eine Funktion erst eine innere Iterator-Funktion
erzeugt, ebenfalls übergehen.


	def erstelle_iterator(start):
		yield start + 1
		yield start * 2
		yield start / 3


	# Iterator erstellen
	iter = erstelle_iterator(10)

	# Iterator anwenden
	for param in iter:
		print param


Iteratoren sind ein Muster, das man mit funktionalen Elementen relativ
einfach zusammenbauen kann. Und zwar sehr viel einfacher, als in reinen
OO-Sprachen wie Java. Aber in Python (und auch Ruby, AFAIR) kann man sie
eben direkt verwenden, und direkt ablaufen lassen. Das erspart jeweils
eine Ebene von verschachtelten Funktionen. Man kann sich "direkter"
ausdrücken, das erleichtert das Verstehen von Code enorm. Und eben diese
bessere Lesbarkeit ist es, die den Python-Leuten wichtig ist.

Diese Syntax ist IMHO vorallem deshalb naheliegender und intuitiver,
weil man nun in Python mit Iteratoren genauso umgeht wie mit Listen.
Zum Vergleich das selbe Beispiel, diesmal mit Liste:

	def erstelle_iterator(start):
		[start + 1, start * 2, start / 3]


	# Iterator erstellen
	iter = erstelle_iterator(10)

	# Iterator anwenden
	for param in iter:
		print param

Man man Iteratoren genauso handhaben wie Listen, und in seiner Denk-
Ausdrucksweise braucht man also nur noch an Listen zu denken, obwohl
man es u.U. mit Iteratoren zu tun hat. Das finde ich in Python sehr
angenehm.

Beim funktionalen Ansatz hingegen muss man mit den Iteratoren wie mit
verschachtelten Funktionen umgehen, und sie ständig auf diese Weise
im Hirn halten. Python löst diesen Knoten :-)  Im ersten Beispiel
(funktionaler Ansatz) wäre einiges umzuschreiben, wenn
"erstelle_iterator" nun keine Iteratorfunktion, sondern eine Liste
zurückgeben würde. Deshalb finde ich, dass Iteratoren genauso wie Listen
von Programmiersprachen explizit unterstützt werden sollten, auch in
Funktionalen Sprachen .. damit man sie wie Listen handhaben kann und
nicht wie Funktionen.


Und nun zu einem weiterem Standard-Konstrukt: map/filter. Sie werden
eingesetzt, um verschachtelte For/If - Anweisungen darzustellen. Nehmen
wir eine Liste von Zahlen, suchen alle geraden Zahlen heraus, und und
halbieren sie. Was übrig bleibt, und kleiner als 10 ist, soll ausgegeben
werden. Vorab:

	def ausgabe(i):
	    print i

	def kleiner10(j):
	    return j<10

	def gerade(i):
	    return i%2 == 0

	def durch2(i):
	    return i/2

	liste = [-7,3,4,5,100,18]

Offenbar müssten 2 und 9 rauskommen. Zunächst als For-Schleife:

	for i in liste:
	    if gerade(i):
	        j = durch2(i)
	        if kleiner10(j):
	            ausgabe(j)

Nun die funktionale Variante mit map/filter:

	map(ausgabe,filter(kleiner10,map(durch2,filter(gerade,liste))))

Wollen wir nichts ausgeben, sondern eine Liste zurück haben, sieht die
funktionale Variante so aus:

	filter(kleiner10,map(durch2,filter(gerade,liste)))

Nun definieren wir die Funktionen inline, damit wir ein gutes
Vergleichsbild haben, schließlich geht es um Lesbarkeit, und jeder
trivalen Funktion einen Namen zu geben war etwas übertrieben. Für
Inline-Funktionen gibt es in Python den lambda-Operator:

	filter(labda i: i<10,map(labda i: i/2,filter(lambda i: i%2 == 0,liste)))

Via Listcomprehensions sieht das der For/If-Konstruktion wieder ähnlicher:

	[i for i in [j/2 for j in liste if j%2 == 0] if i<10]

Das ist IMHO leichter zu lesen. Und das sage ich nicht, weil ich keine
funktionalen Konzepte kenne oder nicht intensiv damit gearbeitet hätte,
sondern einfach als pragmatischer Python-Programmierer, der beide
Varianten zur Auswahl hat und schaut, was besser lesbar ist.

Funktionale Elemente werden damit nicht komplett aus Python verbannt.
Lediglich die typpischen map/filter - Konstruktionen bekamen eine
schönere Syntax durch mehr Ähnlichkeit zu for/if - Konstrukten.

Alles weitere findest du im Python-Tutorial. Das ist wirklich
interessantes Zeug. Da fällt mir ein, dass ich auch mal wieder mehr in
Haskell machen sollte. :)

> Oder findest Du while/for loops einfach sexy?

Ich finde sie besser lesbar.

> > > Hmhh, klingt so, als ob die bei Python noch nach sinnvoller Implementierung
> > > suchen und suchen.
> > 
> > Nein, sie haben sie gefunden! Sie sind deswegen gerade dabei,
> > funktionalen Overhead wie lamda, map, filter etc. zu verbannen und
> > langfristig abzuschaffen, weil eben Listcomprehensions und Generator
> > Expression einfacher und mächtiger sind.
> 
> Warum hat man dann bei Haskell diese Sachen noch nicht verbannt?
> Du meinst wirklich, die sind nicht notwendig?

Huch, sorry, hab ich mich falsch ausgedrückt. Ich meinte natürlich nicht
alle funktionalen Elemente, sondern nur map und filter, weil sie gegen
naheliegendere Konstrukte ersetzt wurden, sowie den lambda-Operator,
weil inline-Funktionen eigentlich fast nur dazu benutzt wurden, diese
map/filter - Aktionen lesbarer zu machen, was ja nun auf anderem
Wege noch besser erreicht wurde, und nicht nur für auf Listen, sondern
auch Iteratoren anwendbar ist. Mal ein ganz primitiver Iterator-Generator:

	def iter_gen():
		yield -7
		yield 3
		yield 4
		yield 5
		yield 100
		yield 18


	iter = iter_gen()

	print [i for i in [j/2 for j in iter if j%2 == 0] if i<10]
	# liefert: [2, 9]

Die Listcomprehensions funktionieren also auch mit Iteratoren. Problem
bei beiden Ansätzen, egal ob map/filter oder Listcomp.: Es werden intern
Listen erzeugt, die von einem map/filter an den nächsten gehen. Liefert
list_gen() einen riesigen Iterator, gibt das ein kleines Speicherproblem.

Deshalb gibt es neben Listcomp. eine weitere Syntax, die statt Listen
Iteratoren erzeugt:

	iter2 = (i for i in (j/2 for j in iter if j%2 == 0) if i<10)

iter2 ist keine Liste, verbraucht keinen unnötigen Speicher, und die
Berechnungen (insbesondere die Traversierung des ersten Iterators) finden
erst statt, wenn man iter2 iteriert. Aber besonders cool ist, dass man
ihn trotzdem fast genauso wie eine Liste behandeln kann:

Unseren iter2 können wir so ablaufen:

	for i in iter2: print i

oder in eine Liste umwandeln:

	list(iter2)

	# liefert: [2, 9]

Was ganz besonders cool ist und durch Closures (den "yield"-Kram) erst
ermöglicht wird: Mann kann den Iterator auch als Objekt ansehen und manuell
traversieren:

	print iter2.next()
	# liefert: 2

	print iter2.next()
	# liefert: 9

	print iter2.next()
	# wirft die Exception "StopIteration"

d.h. trotz der vielen verschachtelten Schleifen bzw. Funktionen braucht
man den Kontrollfluss nicht abzugeben.


> > Im Vergleich zu Java vielleicht. Aber bei Python ist das wirklich nur
> > eine Frage deines konkreten Problems. Aber wiegesagt, man müsste
> > jemanden haben, der mit beiden intensiv gearbeitet hat, um das
> > einschätzen zu können.
> 
> Codeaussehen ist auch Geschmacksfrage. Aber die Sache mit der
> Typprüfung ist fundamentalk im Finden von Fehlern.
> Da kann ich mit Python nix anfangen.

Python hat ne Menge anderer Vorzüge. Auch in Python kannst du
funktional, OO, sonstwas programmieren. Der Hauptunterschied zu Ocaml
ist sicher die dynamische statt statische Typisierung, was du als
Nachteil ansiehst, aber im Gegenzug bietet Python im Prinzip alles,
was man aus ner Sprache rausholen kann, und vorallem eine schöne
einfache Syntax, die die häufigsten Standardprobleme einheitlich
erschlägt. Das Iterator-Konzept gibt es in Ocaml nicht, oder?
Da geht man funktional ran, wie ich es hier in Python gezeigt habe,
oder?

> > > Und? Gibt es da Funktoren?
> > > Kannst Du ein Modul und ein weiteres Modul nehmen und eine
> > > Funktion darauf ansetzen um ein neues Modul zu erzeugen?
> > 
> > Nö, ist aber auch nicht wirklich nötig. Aber mit Klassen und Funktionen
> > kann man das, und dann braucht man das nicht mehr ganz oben auf Modul-
> > Ebene.
> 
> Wozu Klassen?
> Warum OO, wenn es auch ohne geht? :-)

Wenn OO mir dir Arbeit erleichtert und meinen Code besser lesbar macht,
dann nehme ich das. Dabei greife ich gelegentlich auf funktionale
Elemente zurück, wenn ich z.B. einfach nur ne Funktion und nicht ein
ganzes Objekt übergeben will.

> [...]
> > > Unter "Intent" steht dort auf S. 151:
> > > 
> > >    "Decouple an abstraction from it's implementation so that the two
> > >     can vary independently."
> > > 
> > > Also, wenn ich das jetzt richtig verstehe (kannst ja korriegieren, wenn
> > > es nicht stimmt), geht es darum, Interface und Implementierung trennen zu können.
> > > Hmhhh. Wenn ich IMplemetierung und Interface voneinander trennen sollte,
> > > habe ich mehrere Module mit unterschiedlicher Implementierung und
> > > oräge dort allen eine einzige Signatur auf.
> > > Dann kann man den Code verändern, aber das Interface bleibt gleich.
> > 
> > Keine Ahnung, was das soll. Du hast eben nur triviales Zeug von dir
> > gegeben, und offenbar das Kapitel gar nicht gelesen.
> 
> OK: überflogen hab' ich's :)

Lies es ordentlich, bevor du so einen Müll hier schreibst.

> > Der Aufwandt für beides bleibt also stets konstant, statt
> > immer größer zu werden, je mehr das Projekt wächst.
> 
> Ja, so dachte ich es mir auch.
> 
> Konkret ausgetüftelt mit OCaml habe ich es mir noch nicht.
> 
> Vielleicht gehe ich die Design Patterns mal durch und schaue,
> wie ich die in OCaml -- aber ohne OO, sonst wäre es ja genau das
> selbe, was da im Buch steht -- kodiere.

Bisher hast du alles im Prinzip so gemacht, wie es im Buch steht.
Du hast zwei unterschiedliche Interfaces gehabt, die du vereinheitlichen
willst. Gibt es da eine Zauberfunktion in Ocaml, die das für dich macht?
Nein! Stattdessen hast du einen Wrapper geschrieben. Haargenauso wie ich
es z.B. in Python ebenfalls machen würde, nur nicht in der  Modul-
sondern in der Klassendefinition. Kein wesentlicher Unterschied, du
hast das Rezept aus dem Buch angewendet, nur etwas anders, nämlich
deiner Programmiersprache entsprechend, formuliert. Du hast das Muster
angewendet, statt das Problem irgendwie "anders" zu erschlagen. Zufall?
Wohl kaum.

> Vielleicht sind manche der Patterns auch weiterhin als OO-Patterns überlebensfähig. ;-)

Viele Pattern sind gar nicht OO-spezifisch, sondern beschreiben einfach
sauberes Software-Design! Du wendest die Muster, die darin stehen, in
Ocaml an, aber behauptest gleichzeitig, sie wären antiquiert.

Die einfachen Muster sind nicht der Rede wert, die sollte jeder mal
gesehen haben, würde aber auch selbst drauf kommen, und es in jeder
Sprache ähnlich lösen, weil's eben naheliegend ist.

Kompliziertere Muster werden durch einige Sprachen stark vereinfacht,
aber das schon damals der Fall. Schau mal, wie oft es eine "direkte"
Lösung in Smalltalk gibt, und bei C++ rumgehampelt werden muss. Und
Smalltalk ist ne klassische OO-Sprache. Dass du diese Dinger in Ocaml
ohne Probleme erschlagen kannst, liegt nicht am funktionalen Konzept,
sondern an der gesamten Qualität der Sprache. Wiegesagt, in Smalltalk
hättest du das auch gekonnt.

Und dann gibt es noch Muster, die man weder als Wink mit dem Zaunpfahl,
noch als Workaround für fehlende Sprachfeatures ansehen kann. Zum
Beispiel das Brückenmuster.

> > Übrigens stehe ich gerade auch an so einem Problem, aber es ist gerade
> > so vertrakt, dass ich das Brückenmuster nicht anwenden kann. Jedenfalls
> > nicht so, wie es sich die GoF gedacht haben.
> 
> Tja, vielleicht mal andre Programmierparadigmen nutzen? ;-)

In Python steht mir alles offen. Mein Ziel ist es, den Code wartbar und
unrendundant zu machen, insbesondere also zu vereinfachen. Die einzelnen
Muster, die dabei entstehen, will ich gar nicht in OO oder "funktional"
einordnen.

Zum Beispiel ist das meiste, was du hier gemacht hast, in OO genauso
möglich, wenn man den Begriff "Modul" gegen "Klasse" und den Begriff
"Funktion" gegen "Methode" austauscht. Wieso du da so einen himmelweiten
Unterschied reindichtest, weiß ich nicht. In Python stehen mir alle
Möglichkeiten offen, und ich nutze die, die mir helfen.

Wenn ich z.B. Rechnungen und Kunden verwalte, dann ist es einfach und
naheliegend, zwei Klassen "Rechnung" und "Kunde" zu haben. Alle
Funktionen die konkretes Wissen über den Aufbau einer "Rechnung"
brauchen, gestalte ich als Methoden davon. Mal ganz primitiv gesprochen.
Würde ich das in einer funktionalen Sprache machen, würde letztlich
doch wieder die Funktionen gruppieren, die Rechnungen verwalten, und
die, die Kunden verwalten, etc. und die, die sich auf alles beziehen,
würde ich von beiden Seiten nutzen wollen. Ich hätte also Vererbung,
nur würde ich das irgendwie anders nennen, vielleicht "gemeinsam
genutztes Modul" oder so.

So fundamental wie du sehe ich die Sache nicht, und die Design-Patterns
würde ich auch zu schätzen wissen, wenn ich z.B. in Haskell
programmieren würde.

> > Aus Effizienz-Gründen ist
> > die "Brücke" bei mir etwas komplexer, eine Art Meta-Typ-System.
> 
> Sowas baust Du selbst?
> Das gibt's doch alles schon. :->
[...]
> Erklären ist meist schwer - ein Beispiel sollte her!

Ist nen blöder Name. Nein, sowas gibt's in der Form noch nicht. Ich
zeig's euch mal, wenn ich weiter damit bin. Das Problem lässt sich nur
schwer an kleinen Sachen demonstrieren. Sobald mein Programm ordentlich
läuft, kann ich das Problem, die Idee und die Lösung ja mal vorstellen,
dann ist das Programm der Beispiel-Code dafür. Aber sehr viel einfacher
als mein Programm könnte ein sinnvolles Beispiel auch nicht sein, von
daher lässt es sich wirklich er erklären, wenn das Programm ordentlich
läuft.

> Aber wenn ich bei "Abstract Factory" schaue, scheint das was anderes zu sein,
> als Du hier meinst.
> 
>  "Provide an Interface for creating families of related or dependent
>   objects without specifying their concrete classes."
> 
> Wenn ich das jetzt richtig zuordne (wie gesagt, selten OO-Zeugs in OCaml genutzt)
> ist es das, was OCaml als "class type" bereits spracheigen mitliefert.

In Python auch, weil man Module an Variablen zuweisen kann, und als
Parameter übergeben. Wenn ich also z.B. mehrere GUI-Libraries mit
gleichem Interface habe (ggf. Adaptoren einsetzen), packe ich sie
in eigene Module. Ich wähle mir eins davon aus, importiere es, und übergebe
dieses Modul als Paramter dem Rest des Systems. 100 leichte Varianten
sind noch möglich.

Auch hier: Du erschlägst es nicht mit "funktionalen" Mitteln, sondern
mit sprachlichen Mitteln.

> Aber wenn es schon beim festlegen auf die Sprache solche Probleme gibt.

Wieso? Wo gab es da ein Problem? Wurde schonmal darüber diskutiert?
Falls du diese Diskussion hier meinst: Das ist doch nur eine
Gegenüberstellung. Mit persönlich geht es jedenfalls nicht darum, eine
der beiden Sprache für alle Zeiten für alle Zwecke als "besser" zu
küren, da wäre ich ja schön bescheuert, mir die Freiheit zu nehmen,
nächste Woche mal was in einer anderen Sprache zu versuchen.

Also, was mich angeht, würde ich natürlich Ocaml lernen wollen, also
wenn ich z.B. dein Labanscale-Projekt unterstützen sollte, würde ich
natürlich deine Wahl (Ocaml) voll und ganz akzeptieren.

> BTW: Werde diese Diskussion mal zum Anlaß nehmen,
>      neben Postscript-Ausgabe auch LaTeX-Ausgabe des labscalgen zu generieren.
>      Dann habe ich gleich mal ne nette Idee, das Modulsystem mal konkret
>      zu nutzen.

Schade. Es wäre mir lieber, du würdest stattlessen deine Sprache in ein
"LabanXML" umwandeln lassen, und zwei weitere Konverter schreiben, die
dieses Format nach Postscript bzw. LaTeX bringen. Naja, hab ich an
anderer Stelle ja ausführlich beschrieben.

> > Dies ist übrigens ein Muster, das in Smalltalk, Python etc. nicht mehr
> > nötig ist, weil dort Module und Klassen ebenfalls wie Variablen (bzw.
> > Objekte erster Stufe) behandelt und zugewiesen werden können. So merke
> > ich mir in Python quasi in einer "Variablen", welche Implementierung
> > ich gerade verwenden will.
> 
> Könnte man in OCaml machen, indem man den ode eines bestimmten Moduls auswählt.
> Auch per Variable. So what?

Oh, wieder eine Gemeinsamkeit. Aber gut, das war auch zu erwarten.
Solche Sachen heben Python nicht von high-level-Sprachen (Ocaml, Ruby,
..) ab, sondern eben eher von Java & Co.


Viele Grüße,

	Volker

-- 
Volker Grabsch
---<<(())>>---
Administrator
NotJustHosting GbR



Mehr Informationen über die Mailingliste linux-l