48 Punkte von GN⁺ 10 일 전 | 5 Kommentare | Auf WhatsApp teilen
  • Wichtiger als einzelne Syntaxunterschiede sind die Unterschiede in Bündeln grundlegender Muster; Programmiersprachen lassen sich je nach Wiederholung, Rekursion und Art der Komposition in sieben Ursprachen einteilen
  • ALGOL, Lisp, ML, Self, Forth, APL, Prolog bilden die Kernklassifikation; jede Familie verwendet eine repräsentative Sprache als Referenzmuster, um die Abstammung anderer Sprachen zu beurteilen
  • Neue Sprachen, die eine vertraute Ursprache teilen, sind leicht zu lernen; der Wechsel zu einer fremden Ursprache erfordert jedoch neue Denkpfade und beträchtliche Lernzeit
  • ALGOL steht für um Zuweisung, Bedingungen und Schleifen organisierte Funktionen, Lisp für Makros und Listen als Code, ML für erstklassige Funktionen und Rekursion, Self für Objekte mit Nachrichtenversand, Forth für stackbasierte Syntax, APL für n-dimensionale Arrays und Prolog für Fakten und Suchstrukturen
  • Für alle Programmierer hat die Beherrschung einer ALGOL-Familiensprache Priorität; danach lohnt es sich, SQL zu lernen und anschließend kontinuierlich fremde Ursprachen zu erschließen

Die sieben Ursprachen der Programmierung

  • Bei der Wahl einer Programmiersprache ist das Erlernen von Grundmustern wichtiger als einzelne Syntaxunterschiede; zwischen ähnlichen Sprachfamilien haben Grundstrukturen wie Array-Iteration oder Kombinationsiteration fast dieselbe Form
  • Verschiedene Sprachgruppen unterscheiden sich stark in Wiederholung, Rekursion und Programmaufbau; diese Bündel grundlegender Muster bilden unterschiedliche Ursprachen
  • Das Erlernen einer neuen Sprache mit vertrauter Ursprache ist ein vergleichsweise leichter Wechsel, doch der Übergang zu einer fremden Ursprache verlangt erheblich Zeit und neue Denkpfade
  • Im Softwarebereich werden ALGOL, Lisp, ML, Self, Forth, APL, Prolog als sieben Ursprachen erkannt
  • Jede Ursprache wird anhand einer bestimmten repräsentativen Sprache als Referenzmuster klassifiziert; andere Sprachen werden durch Vergleich mit diesem Muster ihrer Linie zugeordnet
  • ALGOL

    • Programme bestehen aus einer Folge von Zuweisungen, Bedingungen und Schleifen und sind in Funktionen organisiert
    • Viele Sprachen ergänzen dazu Modulsysteme, neue Arten zur Definition von Datentypen, Polymorphie sowie alternative Kontrollflussstrukturen wie Ausnahmen oder Coroutines
    • Die meisten heute weit verbreiteten Programmiersprachen gehören zu dieser Linie der Ursprache
    • Zu ALGOL selbst zählen ALGOL 58, ALGOL 60, ALGOL W, ALGOL 68
    • Assembly language, Fortran, C, C++, Python, Java, C#, Ruby, Pascal, JavaScript und Ada sind mit dieser Familie verbunden
    • Es ist die älteste Ursprache mit einer Linie, die bis zur Formalisierung von Programmen für Babbages Analytical Engine durch Ada Lovelace zurückreicht
    • Auch die Maschinensprache und Assembler der Computer in der Eckert-Mauchly-Architektur von EDVAC bis zu den frühen Univac-Systemen sowie frühe Versuche höherer Programmiersprachen von Grace Hoppers A-0 bis zu Fortran und COBOL gehören zu dieser Form
    • In den 1960er Jahren entwickelte die Wissenschaft strukturiertes Programmieren, um diese Sprachen besser beherrschbar zu machen; das Ergebnis war ALGOL 60, von dem die meisten späteren Mitglieder der Familie abstammen
    • Mit der Zeit besteht die Tendenz, Funktionen anderer Ursprachen zu absorbieren
      • In den 1980er Jahren wurden Konzepte aus der Self-Familie in Form von Klassen eingebaut und als Mittel zur Implementierung von Datentypdefinition und Polymorphie genutzt
      • Seit 2010 tauchen auch Konzepte aus der ML-Familie auf
  • Lisp

    • Eine Syntax aus in Klammern gesetzten Präfixausdrücken in Verbindung mit Listendarstellung
      • (+ 2 3)
      • (defun square (x) (* x x))
      • (* (square 3) 3)
    • Da die Listendarstellung aus in Klammern gesetzten, durch Leerzeichen getrennten Elementen in die Sprache eingebaut ist, hat der Code selbst Listenform
    • Makros können Listen annehmen, verändern und den veränderten Code an den Compiler weitergeben, sodass Programmierer die Sprachbedeutung neu definieren können
    • Beim Schreiben der meisten Programme verhalten sie sich meist wie andere Ursprachen, gewöhnlich ALGOL oder ML, aber das Makrosystem ist das Unterscheidungsmerkmal
    • Auch die loop-Syntax in Common Lisp ist keine eingebaute Sprachfunktion, sondern als Makro definiert
    • Es gab viele frühe Lisp-Varianten, doch die Community fand einen Konsens um Common Lisp
    • Sussman und Steele erforschten, wie weit man mit Funktionen allein kommt, und schufen Scheme
    • Es gibt zweckgebundene Lisps wie Lush für numerische Berechnungen, AutoLISP als Skriptsprache für AutoCAD und Emacs Lisp zur Implementierung des Editorverhaltens in Emacs
    • In jüngerer Zeit ist Clojure als dritter großer Zweig der Lisp-Familie aufgestiegen
    • Es erschien rund ein Jahr nach Fortran und ist die zweitälteste bis heute verwendete Sprachfamilie
    • Ausgangspunkt war die mathematische Frage, wie man eine mathematische Struktur notiert, die ihre eigenen Ausdrücke auswerten kann
    • John McCarthy gab 1958 die Antwort und sie wurde anschließend auf Computern implementiert
    • Frühes Lisp passte wegen seines mathematischen Hintergrunds schlecht zu den damaligen Maschinen; Probleme wie Speicher- und CPU-Zyklen spielten in der Mathematik keine Rolle, weshalb Techniken wie Garbage Collection nötig wurden
    • Ende der 1970er und Anfang der 1980er gab es Maschinen, die von Grund auf nur für die Ausführung von Lisp entworfen wurden
    • Viele Elemente heutiger integrierter Entwicklungsumgebungen wurden auf diesen Maschinen erfunden
    • Zur selben Zeit war Lisp das wichtigste Werkzeug der KI-Forschung; als der KI-Boom der 1980er keine Ergebnisse lieferte, stürzte zusammen mit dem Feld auch Lisp in den AI Winter
    • Dennoch überlebte es, und mit leistungsfähigeren Computern und der Übernahme seiner Funktionen durch andere Sprachen sind die Implementierungshürden geringer geworden
  • ML

    • Funktionen sind erstklassige Werte, und es gibt ein Typsystem der Hindley-Milner-Familie, das vielfältige Funktionen und Tagged Unions ausdrücken kann
    • Jede Wiederholung wird in Form von Rekursion ausgeführt
      • sum [] = 0
      • sum (x:xs) = x + sum xs
    • Es wird auch die Methode genutzt, Funktionen zu definieren, die Wiederholungsmuster kapseln und andere Funktionen entgegennehmen, um das Verhalten umzusetzen
      • map _ [] = []
      • map f (x:xs) = (f x) : (map f xs)
    • Einige Sprachen wie Miranda und Haskell verwenden standardmäßig Lazy Evaluation
    • Andere Sprachen erweitern das Typsystem in verschiedene Richtungen
      • OCaml versucht eine Verbindung mit Konzepten der Self-Ursprache
      • Agda und Idris übernehmen abhängige Typsysteme, die Werte und Typen mischen
      • 1ML verbindet Module und Typen
    • Aus ML gingen CaML, Standard ML, OCaml hervor
    • Verwandte Linien wie Miranda, Haskell, Agda und Idris setzen sich fort
    • ML war die Metasprache eines in Cambridge entwickelten Theorembeweiser-Programms; daher stammt auch der Name
    • Später löste es sich aus diesem Kontext und verbreitete sich als eigenständige Sprache, besonders in Europa mit Schwerpunkt auf Großbritannien und Frankreich
  • Self

    • Programme bestehen aus einer Menge von Objekten, die sich gegenseitig Nachrichten schicken, und jedes Verhalten wird auf diese Weise umgesetzt
    • Neue Objekte werden erzeugt, indem Nachrichten an bestehende Objekte gesendet werden
    • Auch Bedingungen werden über eine Variable ausgeführt, die auf entweder das Objekt true oder das Objekt false verweist
      • Diese beiden Objekte empfangen eine Nachricht mit den Funktionen, die im wahren bzw. falschen Fall ausgeführt werden sollen, als Parameter
      • Das true-Objekt führt die erste Funktion aus, das false-Objekt die zweite
      • Der aufrufende Code weiß nicht, welches Objekt es ist, und sendet nur eine Nachricht
    • Mit Schleifen ist es genauso; erstellt man das passende Objekt und setzt es an die richtige Stelle, lässt sich die gesamte Sprachbedeutung neu definieren
    • Solche Sprachen speichern den Quelltext gewöhnlich nicht als Textdateien, sondern in einer Live-Umgebung
    • Programmierer verändern das Live-System und speichern dessen Zustand, statt Dateien zu kompilieren und daraus ein System zu bauen
    • Wichtige Beispiele sind Smalltalk und Self
    • Viele Sprachen übernehmen nur Teile dieses Nachrichtenversands, und diese partielle Übernahme nennt man gewöhnlich objektorientierte Programmierung
    • Die meisten davon basieren auf Smalltalk; nur JavaScript ist eine Ausnahme und stammt aus Selfs klassenlosem Objektsystem
    • Das Objektsystem von Common Lisp verallgemeinert dies so, dass die Laufzeit den auszuführenden Code nicht nur anhand eines empfangenden Objekts, sondern anhand aller Parameter auswählt
    • Erlang verlagert den Ansatz dahin, dass nicht der Ausführungsfluss zwischen Objekten wandert, sondern parallele Ausführungsthreads explizit Nachrichten empfangen und senden
    • Die Ursprungssprache ist Smalltalk, entwickelt Ende der 1970er und in den 1980ern bei Xerox Parc
    • In den 1980ern gab es mehrere kommerzielle Smalltalk-Systeme, und IBM nutzte Smalltalk zur Entwicklung der Werkzeugfamilie VisualAge für andere Sprachen
    • Heute lebt Smalltalk vor allem als Open-Source-Form Pharo Smalltalk fort
    • Es wurde intensiv erforscht, wie man Smalltalk schnell und effizient ausführt; der Höhepunkt davon war das Strongtalk-Projekt
    • Historisch wichtig ist, dass Entdeckungen aus Strongtalk zur Grundlage des HotSpot JIT-Compilers von Java wurden
    • Smalltalk übernahm die Begriffe Wert und Typ aus früheren Sprachen, um Klassen zu implementieren; jedes Objekt hatte eine Klasse, die ihm einen Typ gab, und diese Klasse erzeugte Objekte dieses Typs
    • Self entfernte das Klassenkonzept und besteht nur aus Objekten
    • Als Referenzmuster dieser Ursprache wurde Self gewählt, weil es die reinere Form ist
  • Forth

    • Stacksprachen sind gewissermaßen das Spiegelbild von Lisp und teilen ihre Syntax mit den Rechnern von Hewlett Packard auf Basis der umgekehrten polnischen Notation
    • Es gibt einen Daten-Stack; schreibt man ein Literal wie 42, wird es auf den Stack gepusht, und Funktionsnamen arbeiten ohne explizite Parameter auf dem Stack
    • Selbst einfache Arithmetik erscheint in umgekehrter Form wie 2 3 + 5 *
    • Auch Funktionsdefinitionen sind sehr kompakt
      • In den meisten Forth-Varianten definiert : ein neues Wort
      • square bedeutet dasselbe wie ein Aufruf von dup und *
      • dup dupliziert das oberste Element des Stacks, * multipliziert die beiden obersten Elemente
    • Man kann den Parser abfangen und durch eigenen Code ersetzen, sodass sich die gesamte Syntax austauschen lässt
    • Forth-Programme, die kleine Sprachen definieren, sind üblich, etwa direkte Parser für Teilmengen von Fortran, Paketlayouts oder ASCII-Diagramme, die Zustandsmaschinenübergänge ausdrücken
    • Dazu gehören verschiedene Varianten von Forth, außerdem PostScript, Factor und Joy
    • Joy ist eine rein funktionale Sprache, die statt eines Stacks eine mathematische Formalisierung von Komposition verwendet
    • Forth wurde 1970 erstmals zur Steuerung eines Radioteleskops geschrieben
    • Danach verbreitete es sich breit in Embedded Systems
    • Forth-Systeme sind leicht genug zu bootstrappen, dass Dutzende Varianten von verschiedenen Programmierern für ihre jeweiligen Zwecke entstanden
    • PostScript erschien in den 1980ern als flexibles Mittel, um Dokumente auf Druckern zu beschreiben
    • PostScript ist in vieler Hinsicht eingeschränkter als Forth, definiert aber grundlegende Operationen für grafisches Layout direkt in der Sprache
  • APL

    • In dieser Sprache ist alles ein n-dimensionales Array
    • Operatoren bestehen aus einem oder zwei Symbolen und führen High-Level-Operationen auf ganzen Arrays aus
    • Die Darstellung ist extrem kompakt, sodass die Symbolfolge selbst zum Kennzeichen der Operation wird, ohne dass weitere Namen nötig sind
    • Ein Beispiel für die Berechnung des Mittelwerts der Variablen x ist (+⌿÷≢) x
    • APL, J, K sind repräsentative Beispiele
    • Höhere Array-Operationen wurden teilweise in viele andere Umgebungen exportiert, etwa MATLAB, NumPy und R
    • APL begann mit einer von Kenneth Iverson in den 1960ern entwickelten mathematischen Notation und wurde später auf Computern implementiert
    • Seitdem hat es unter Menschen mit schweren Rechenaufgaben eine beständige Nischenanhängerschaft
    • Die Nachfolgesprache K war im Finanzumfeld sehr populär
  • Prolog

    • Programme bestehen aus einer Menge von Fakten
      • father(bob, ed).
      • father(bob, jane).
    • Verwendet werden auch nicht geerdete Fakten, die mit Variablen neue Fakten aus anderen Fakten ableiten
      • grandfather(X, Y) :- father(X, Z), father(Z, Y).
    • Die Prolog-Laufzeit nimmt diese Fakten und Anfragen entgegen und führt eine Suche aus, um Ergebnisse zu finden
    • Wählt man die Struktur der Faktendefinitionen passend, ergibt sich Turing-Vollständigkeit
    • Die Terme, aus denen Fakten in Prolog bestehen, sind selbst ein eigener Datentyp, der erzeugt und an die Laufzeit übergeben werden kann
    • In dieser Hinsicht nimmt Prolog eine ähnliche Position ein wie Makros in Lisp oder Parserersatz in Forth
    • Da Prolog-Programme im Kern Suche sind, erfolgt Optimierung ähnlich wie bei Datenbankabfragen über Steuerung der Suchreihenfolge und frühes Abschneiden erfolgloser Pfade
    • Dazu gehören Prolog, Mercury, Kanren
    • Der größte Teil der tatsächlichen Programmierung in dieser Ursprache findet in Prolog selbst statt, und die Einheitlichkeit der Community ist sehr hoch
    • In den 1970ern erkannten Logiker in Frankreich, dass sich Programme als Prädikatenlogik erster Stufe ausdrücken lassen, und begannen mit Implementierungsversuchen
    • Das japanische Projekt für Computer der fünften Generation setzte in den 1980ern stark auf Prolog, doch mit dem Scheitern des Projekts litt auch Prologs Ruf
    • Unabhängig davon wurde über Jahrzehnte weiter erforscht, wie sich Prolog-Laufzeiten in den meisten Fällen effizient machen und um neue Funktionen erweitern lassen
    • Mit Funktionen wie numerischen Constraints entwickelte sich daraus Constraint Logic Programming
    • Prolog taucht weiterhin in Nischenbereichen auf
      • Die Typprüfung von Java war über viele Jahre in Prolog implementiert
      • Auch Facebooks frühes Werkzeug zur Quellcodesuche basierte auf Prolog

Wie man das nutzen kann

  • Vielen Programmierern mögen einige oder alle dieser Sprachfamilien sehr fremd erscheinen, doch wegen der Denkpfade und neuen Möglichkeiten, die jede von ihnen eröffnet, lohnt sich die Investition von Zeit
  • Aus ALGOL-Sicht wirken zwei Dinge oft völlig verschieden, die aus einer anderen Perspektive nur einen trivialen Vergleich darstellen
  • Prioritäten

    • Alle Programmierer sollten eine Sprache der ALGOL-Familie gut beherrschen
    • Danach wird empfohlen, SQL als Sprache der Prolog-Familie zu lernen
      • In der Karriere bringt sie nach ALGOL den größten Nutzen
  • Danach erweitern

    • Hat man diese beiden Familien gelernt, ist es langfristig vorteilhaft, jedes Jahr eine neue Sprache aus einer fremden Ursprache zu lernen
    • Die vorgeschlagenen Sprachen und Reihenfolgen pro Familie sehen so aus
      • Lisp: PLT Racket
      • ML: Haskell
      • Self: Self
      • Prolog: Prolog
      • Forth: gForth
      • APL: K, verwendet über ok
  • Reihenfolge anpassen

    • Wer viel numerisch rechnet, sollte K früher lernen
    • Wer viel Embedded Programming macht, sollte gForth früher lernen
    • Die Reihenfolge selbst oder die genaue Wahl der Sprache ist jedoch nicht entscheidend
    • Statt Haskell kann man auch Standard ML oder OCaml lernen, statt PLT Racket auch Common Lisp, statt gForth auch Factor
  • Ergänzungen aus den Fußnoten

    • Auch nach dem Lernen von SQL besteht weiterhin die Notwendigkeit, Prolog selbst zu lernen
      • Denn die tatsächliche Verwendung unterscheidet sich deutlich von SQL
    • Nach Lesermeinung ist ein üblicher Weg zum tiefen Verständnis von Forth, selbst eine Forth-Implementierung zu schreiben
      • Es wird erwähnt, dass Forth klein genug ist, dass eine Person es in relativ kurzer Zeit von Grund auf implementieren kann
      • gForth ist eine gute Implementierung, um ANS Forth zu lernen
      • Als Lernmaterial wird McCabes FORTH Fundamentals, Volume 1 genannt
      • Als weitere Forths werden PygmyForth, eForth, colorForth genannt

5 Kommentare

 
zkj9404 9 일 전

Interessant.

 
tazuya 9 일 전

Während des Studiums habe ich Fächer gelernt und Aufgaben bearbeitet, die auf der ALGOL-Familie, Lisp und Prolog basierten – das weckt Erinnerungen.

 
mhcoma 9 일 전

Diese Sprachen haben moderne Mainstream-Programmiersprachen stark geprägt,
aber darunter scheint nur Forth vergleichsweise wenig Einfluss gehabt zu haben.

 
click 9 일 전

Auch wenn ich mich mit Präfixnotation noch anfreunden könnte, ist das Codieren in Postfixnotation einfach viel zu umständlich.

 
GN⁺ 10 일 전
Hacker-News-Kommentare
  • Im PL-Kurs an der Tufts haben wir für die ersten vier Sprachfamilien vor imperativen Sprachen, Lisp, ML und Smalltalk jeweils selbst eine Mini-Version gebaut, und es freut mich, dass dieser Prozess inzwischen sogar als Lehrbuch erschienen ist. Schade ist nur, dass der frühere Prolog-Teil fehlt

    • Es wäre wirklich großartig, wenn irgendwo, etwa im Internet Archive, noch eine Ausgabe inklusive des fehlenden Prolog-Teils auftauchen würde
  • Wenn ich an der Einordnung in diesem Artikel nur eine Sache ändern dürfte, dann wäre es, Ruby nicht als Algol-Familie, sondern klar als objektorientierte Sprache zu sehen. Der Einfluss von Smalltalk ist groß, und selbst in Namen der Standardbibliothek sieht man Spuren davon, etwa collect statt map. In Ruby ist von Anfang bis Ende alles ein Objekt, und Methodenaufrufe lassen sich am natürlichsten als das Senden von Nachrichten an Objekte verstehen. Es wird oft mit Python verglichen, aber die Entwicklungspfade waren ziemlich unterschiedlich, auch wenn beide heute gefühlt an einem ähnlichen Punkt im Ökosystem angekommen sind. Für mich fühlt sich Ruby eher wie ein kuscheliges Alpaka an als Python

    • Auch Python kann man seit den new style classes faktisch als reine OOP-Sprache sehen. Bei Hello World fällt das weniger auf, aber selbst die Basistypen sind inzwischen allesamt Objekte. Wenn jemand OOP nicht mag, kann man mit type(42) und dir(42) gut zeigen, dass sogar eine Ganzzahl ein Objekt ist
    • Ich habe eher das Gefühl, dass die Methode, eine bestimmte Ursprache eindeutig als objektorientierte Sprache festzunageln, die Leute eher verwirrt. OO ist wie prozedural eher ein Programmierstil als eine einzige Sprachkategorie; Python und C++ nur wegen Mehrfachvererbung derselben Sprachart zuzuordnen, erscheint mir zu grob
    • Die Kamel-Metapher erinnert mich daran, dass camel ursprünglich nicht eher ein Symbol aus der Perl-Welt war?
  • Ich würde in die Sprachgenealogie noch eine Kategorie für Sprachen zur Darstellung von Beweisen aufnehmen. Das sind Sprachen, in denen Programme über die Curry-Howard-Korrespondenz zugleich Beweise sind; Lean ist ein typisches Beispiel. Man kann sie als Unterkategorie funktionaler Sprachen sehen, aber weil ihr Hauptzweck eher Verifikation als Ausführung ist, finde ich eine eigene Achse sinnvoll

    • Für mich sehen Theorem Proving und komplexe Typsysteme eher wie Erweiterungen bestehender Sprachen aus. Agda und Idris sind funktionale Sprachen mit komplexen Typen, Isabelle und Lean fügen dazu noch interaktives Beweisen hinzu. Dafny ist eher imperativ plus Theoreme und Hinweise, und ACL2 lässt sich gut als Lisp mit theorem/hint verstehen. Und wie man an Rust traits sieht, wirken typeclasses auf funktionalen wie imperativen Sprachen wie eine Art logische Programmierung
    • Solche Systeme sind per Definition nicht Turing-vollständig, deshalb fällt es mir schwer, sie als echte Programmiersprachen zu sehen. Wären sie Turing-vollständig, könnte man mit nicht terminierenden Programmen falsche Beweise konstruieren
    • Ich sehe diese Strömung letztlich als direkt aus ML abgeleitet
    • Lean ist eindeutig eine dependently typed ML-family-Sprache in der Nähe von Agda und Idris, daher kann man sie im großen Bild durchaus unter ML einordnen. Und ich glaube nicht, dass das langfristige Ziel von Lean darin besteht, Ausführung als bloße Nebensache zu behandeln. Microsoft interessiert sich für das Schreiben realer Software. Wenn man umgekehrt stärker betont, dass es eine „Sprache zum Ausdrücken von Beweisen“ ist, darf Prolog ebenfalls nicht fehlen; dann könnte man Lean halb als ML, halb als Prolog sehen. Aus dieser Perspektive wirkt die Curry-Howard-Korrespondenz wie eine von mehreren Möglichkeiten, Logik des Rechnens umzusetzen
  • Ich habe mir vor Kurzem wieder ein Sprachvergleichsprojekt angesehen; dort ging es um einen Benchmark, der 3.715.891.200 signed permutations von 10 Zeichen parallel zyklisch zerlegt. Mich interessierten weniger die „Ursprachen“ als vielmehr moderne Implementierungen der jeweiligen Paradigmen, also Sprachen, die man für Forschungsprogrammierung tatsächlich wählen würde. Ich habe nicht nur auf Performance geschaut, sondern auch darauf, wie gut sie sich mit AI-Unterstützung nutzen lassen und wie angenehm ich den Code lesen und durchdenken kann. Dank AI war es auch möglich, jede Sprache ziemlich tief zu optimieren, also eine Art Tourismus durch verschiedene Sprachwelten zu machen. Die Ergebnisse stehen hier, und besonders überraschend fand ich, dass F# ganz oben landete

    • Auf den ersten Blick wirkt das überraschend, aber ich denke, die Details sind entscheidend. Wenn man Lean ausnimmt, sind die Unterschiede insgesamt nicht extrem, und dass Chez 2,5-mal langsamer als C++ ist, ist für eine dynamisch typisierte JIT-Sprache eigentlich ziemlich respektabel. Dass F# bei solchen Aufgaben stark ist, dürfte vor allem daran liegen, dass die Erfahrung mit Parallelisierung auf .NET Core besonders ausgereift und solide ist. Falls diese Zahlen elapsed time sind, wäre eine Aufschlüsselung nach CPU time zusätzlich interessant. Außerdem unterscheiden sich die Parallelisierungsstrategien je nach Sprache etwas, also ist es kein Vergleich unter völlig identischen Bedingungen. Zum Beispiel können F#s einfache Thread-Aufteilung und Rusts paralleler Iterator aus Rayon ganz unterschiedliche Overhead-Profile haben. Am Ende könnten Rust und C++ mit sorgfältig genutzten niedrigstufigen OS-Concurrency-Primitives noch schneller werden, aber das wäre schon wieder eine andere Art von Vergleich. Auch ist unklar, ob man etwa die Nutzung von C FFI aus C oder Haskell zulassen sollte, weshalb in solchen Vergleichen zwangsläufig viel qualitative Beurteilung steckt. Beim Chez-Code könnte zudem noch Luft nach oben sein, wenn man Permutationen in fxvector speichert und auf fixnum-spezifische Operationen setzt, um Boxing/Unboxing und Allokationen zu reduzieren. Dazu gibt es passende Infos in der Chez-Scheme-Objektdokumentation
  • Ich habe selbst einmal einen ähnlichen Artikel hier geschrieben. Bei Algol, Lisp, Forth, APL und Prolog stimme ich zu, aber als innovative funktionale Sprache habe ich SASL aufgenommen, das ML etwas vorausging, und als objektorientierten Vertreter Smalltalk statt Self gewählt, weil es früher da war. Dazu habe ich Fortran, COBOL, SNOBOL und Prograph aufgenommen, weil ich sie jeweils für Sprachen halte, die das Feld auf eigene Weise verändert haben

    • Diese Liste gefällt mir besser. Besonders freut mich, dass SNOBOL darin vorkommt. Ich habe es zwar nie selbst benutzt, aber als Kind habe ich den Namen zum ersten Mal gesehen, als ich bei einem Buchflohmarkt der Stadtbibliothek wegen des witzigen Namens ein Buch dazu in die Hand nahm. Davor kannte ich nur BASIC, Logo und ein wenig 6502-Assembler, den ich aus Beispielen im Atari-BASIC-Handbuch aus BASIC heraus aufgerufen hatte. Und bei einer Liste innovativer Sprachen kann ich mir kaum vorstellen, Fortran und COBOL oder ihren Vorläufer FLOW-MATIC wegzulassen. Das erwähnte Buch war das Atari BASIC manual
    • Ich verstehe nicht ganz, warum Smalltalk statt Self nicht in der Liste gelandet ist. Smalltalk war früher da, und Alan Kay hat sogar den Begriff „OOP“ selbst geprägt. ML sehe ich genealogisch ohnehin eher als Kind von Lisp
  • Ich würde dieser Diskussion noch semantische Familien hinzufügen. Gemeint sind etwa Verilog, Petri nets, Kahn process networks, dataflow machines, process calculi, reactive, term rewriting, constraint solver/theorem prover-Familien und probabilistic programming. Außerdem fallen mir Sprachen wie Unison, Darklang, temporal dataflow oder DBSP ein, die nicht sauber in die bestehenden sieben Kategorien passen, aber praktisch schon nah an produktionsreifen Systemen sind. Das mag etwas nach Mogeln klingen, aber sie beruhen auf Rechenmodellen, die parallel zum von-Neumann-Modell stehen. Ich wollte schon länger einmal einen Artikel schreiben wie „alle Arten des Rechnens, die wir kennen, jenseits von von Neumann“

    • So einen Artikel würde ich mit großer Freude lesen. In der Zwischenzeit musste ich wieder an Teile eines Textes von Steve Yegge denken. Der Kern war, dass ein Großteil der heutigen Informatikausbildung im Grunde auf dem von von Neumann geprägten Rahmen aufbaut und dass die Entscheidung für sequentielle Maschinen auch eine Folge der damaligen Realitäten bei Herstellungskosten und Geschwindigkeit war. Eindrucksvoll fand ich auch die Aussage, dass viele Dinge, die wir lernen – Maschinenarchitektur, Verzweigungen, Schleifen, Subroutinen, Debugging, Zahlensystemumwandlung, Problemmodellierung –, bereits in seiner Arbeit angelegt waren. Das Zitat dazu ist im Archiv zu finden
    • Beim Thema term rewriting musste ich daran denken, wie ich im Studium an einer Tabellenkalkulation gearbeitet und den Formelausdrucksparser übernommen habe. Ich hing zunächst eine Woche lang fest, bis mir klar wurde, dass ich 1+1 einfach in etwas wie ADD(1,1) umschreiben konnte und es dann mit den Mitteln parsen konnte, die ich schon beherrschte. Weil ich mich außerdem sinnlos gegen das Lernen von Regex gesträubt hatte, wurde der Code ziemlich eigenartig, und ich erinnere mich noch an den Satz eines Kollegen: „Lasst es lieber in Ruhe, Andy bekommt es schon hin.“ Jemand aus einem anderen Team hat es mit Regex in ungefähr einem Zwanzigstel meines Codes gelöst
    • Zu der Formulierung „aufstrebende, praxisreife Sprachen“ würde ich ergänzen, dass für mich auch Systeme wie ChatGPT, obwohl vielleicht noch nicht vollständig production-ready, in eine ähnliche Kategorie fallen, weil sie bereits real im Arbeitsalltag eingesetzt werden. Ob man sie als Programmiersprachen bezeichnen sollte, ist streitbar, aber als Medium, mit dem Menschen Computern sagen, was sie tun sollen, kann man das durchaus so sehen. Auch Nichtdeterminismus halte ich nicht für ein Ausschlusskriterium für Programmiersprachen
    • Die Texte von Sussman über propagators sind in dem Zusammenhang ebenfalls sehenswert
    • Als Beispiel für logic programming in S9 Scheme fand ich dieses Material ziemlich gut. Man muss das Buch nicht einmal kaufen, sondern kann den Code direkt herunterladen, und wenn man sich mit einer Einführung wie Simply Scheme die Grundlagen aneignet, lässt sich die Struktur des Solvers recht leicht nachvollziehen
  • „Concepts of programming languages“ an der TU Delft war mein Lieblingskurs im Informatikstudium. Wir haben C, auf der funktionalen Seite Scala und für Prototypkonzepte JavaScript gelernt, und dadurch fiel es mir Jahre später deutlich leichter, Elixir zu lernen. Außerdem gab es einen Kurs, in dem man Unreal-Tournament-Agenten in GOAL, einer auf Prolog basierenden Sprache, programmiert hat. Lange wusste ich nicht, wofür ich Prolog sinnvoll einsetzen könnte, aber am Ende habe ich es verwendet, um eine Rechtschreibprüfung zu bauen, die von LLMs erzeugte miserable Papiamentu-Sätze iterativ korrigieren lässt

    • Ich hatte einen ähnlichen Kurs, und obwohl der Professor nicht besonders gut war, bin ich sehr froh, ihn belegt zu haben. Schon ein sehr oberflächlicher Überblick über andere Ursprachen erweitert den Horizont deutlich, und mit Assembler noch mehr. Selbst wenn man nichts davon direkt produktiv einsetzt, vermeidet man eher die Falle, mit einem Hammer in der Hand jedes Problem wie einen Nagel zu sehen
    • Ich war auch in dem Kurs. Der Unreal-Tournament-Teil war einer der coolsten Kurse, die ich je gesehen habe, und soweit ich weiß, wurde er schon im Jahr nach mir abgeschafft. Schade, dass daraus wohl ein ganz normaler AI-Kurs geworden ist, wie ihn inzwischen alle haben. Ich habe zwar bis heute nicht viele gute Einsatzfelder für Prolog gefunden, aber GOAL hat auf mich einen deutlich stärkeren Eindruck gemacht. Und erst vor Kurzem wurde mir mit etwas Frust klar, dass man seine Struktur auch in „normaleren“ Sprachen nachbilden kann – mit vielen der gleichen Vorteile
    • Ich habe mich gefragt, ob mit GOAL hier Game Oriented Assembly Lisp gemeint ist
  • Ich stimme der These zu, dass man Sprachen aus unterschiedlichen Kategorien lernen sollte. Erst durch OCaml fühlten sich Funktionen für mich wirklich wie mathematische Funktionen an, Mathematica hat mir beigebracht, Ausdrücke selbst als Eingabe zu betrachten, und die umgekehrte polnische Notation von PostScript hat mein Denken weit über einfache Arithmetik hinaus komplett neu verdrahtet. Der Behauptung, dass es egal sei, ob man Java, C#, C++, Python oder Ruby wählt, stimme ich aber nicht zu. Wenn das Ziel nur darin besteht, Quicksort zu implementieren, mag das ähnlich sein, aber sobald jemand tatsächlich etwas bauen will, macht die Sprachwahl einen Unterschied wie Tag und Nacht. Wer 3D-Spiele entwickeln will und zuerst Ruby in die Hand bekommt oder wer explorative Data Science oder Deep Learning machen möchte und zuerst Java bekommt, verliert womöglich schnell die Motivation

    • Mit Rust werde ich wahrscheinlich nie Geld verdienen, aber ich bereue trotzdem kein bisschen, es gelernt zu haben. Rust hat mich dazu gebracht, über Dateneigentum in Programmen wirklich tief nachzudenken
  • Dieser Artikel erinnert mich an Bruce Tates 7 languages in 7 weeks. Darüber bin ich auch zum ersten Mal auf Erlang gestoßen. Historisch erscheint es mir allerdings etwas gewagt, COBOL und Fortran in die Algol-Familie einzuordnen, auch wenn die Geschichte einen eben daran erinnert, dass jede Darstellung immer ein Stück weit reduktiv ist

    • Ich halte es auch für problematisch, noch weiter zurückzugehen und eine primitive Urklassifikation festzulegen. Die ersten Assembly-Sprachen waren ebenfalls imperativ, aber interessant an Algol, Fortran und Cobol war, dass sie mit Funktionen und anderen Hochsprachenmerkmalen komplexe Programmierung ermöglichten. Die meisten Nachfahren hat Algol, aber die erste imperative Programmiersprache war aus meiner Sicht Fortran
    • Wenn man nur auf Wikipedia schaut, sieht es so aus, als seien Fortran und Algol beide ungefähr 1957 entwickelt worden. Mich würde interessieren, welche tatsächlich früher war und ob es im Entwurfsprozess gegenseitige Einflüsse oder Überschneidungen gab
    • Vielleicht ist es treffender, COBOL als lebendes Fossil zu sehen. Und das heutige Fortran wirkt auf mich wie eine Sprache, die auf der FORTRAN-Familie basiert, aber Eigenschaften der Algol-Linie durch horizontalen Transfer übernommen hat
  • Dazu gab es auch schon früher eine HN-Diskussion. Die frühere Debatte hilft beim Einordnen des Kontexts

    • Genauer gesagt war das die Diskussion vom 4. Mai 2023 mit 323 Kommentaren. Noch älter ist dieser Thread vom 30. September 2021; damals gab es 29 Kommentare