1 Punkte von GN⁺ 2024-11-10 | 1 Kommentare | Auf WhatsApp teilen
  • λ-2D ist ein Sprachexperiment, bei dem Zeichnungen selbst zum Code werden, und zielt zugleich auf visuelle Ausdrucksformen, die sich in Textsprachen nur schwer fassen lassen, sowie auf die ästhetische Form von Programmen
  • Das Gerüst der Sprache ist der Lambda-Kalkül; der Ausgangspunkt ist die Idee, dass eine Struktur, die eher einer Auswertung als einer festgelegten Ausführungsreihenfolge ähnelt, der Art verwandt ist, wie wir ein Bild betrachten
  • Um leicht von Hand gezeichnet und zugleich maschinell interpretiert werden zu können, verwendet sie gitterbasierte Symbole und Drähte, um den Datenfluss darzustellen
  • Da reiner Lambda-Kalkül in der Praxis wenig benutzbar ist, wurden syntaktischer Zucker und Interaktionselemente wie Zahlen, mathematische Operatoren, Frames und Slider ergänzt
  • Die aktuelle Implementierung wandelt λ-2D-Programme zur Ausführung in einen einzelnen JavaScript-Ausdruck um; Grenzen wie ein eher schaltplanartiges Erscheinungsbild sowie Herausforderungen beim Lernen und Scannen bleiben bestehen

Ein Sprachexperiment zum Codieren mit Zeichnungen

  • λ-2D ist ein Experiment für eine nichtsprachliche Programmiersprache, das mit der Frage beginnt, ob man „durch Zeichnungen programmieren“ kann
  • Sprachen jenseits von Text gibt es bereits in mehreren Richtungen
  • Die Designziele lassen sich auf drei Punkte verdichten
    • Die Tatsache ausnutzen, dass Programme gezeichnet werden, um Funktionen einzubauen, die in textbasierten Sprachen nur schwer umzusetzen sind
    • Vermeiden, dass es entweder so wenige Befehle gibt, dass selbst einfache Programme schwierig werden, oder so viele, dass die Sprache nicht mehr minimalistisch ist und Computer-Vision-Verarbeitung erschwert wird
    • Das Programm selbst soll visuell so attraktiv sein, dass es zu einer Zeichnung wird, die man am liebsten gerahmt aufhängen würde

Lambda-Kalkül und gitterbasierte Darstellung

  • λ-2D basiert nicht auf einem imperativen oder Low-Level-Ansatz, sondern auf dem Lambda-Kalkül
  • Der Lambda-Kalkül ist eher „Auswertung“ als „Ausführung“ und berührt damit die Art, wie der Blick beim Betrachten einer Zeichnung ohne feste Reihenfolge Punkten, Linien, Formen und Komposition folgt
  • Die anfängliche Struktur ist ein gitterbasiertes System
    • Nutzer können durchgehende Linien zeichnen, die sich über mehrere Gitter erstrecken
    • Jedes Gitter wird letztlich als eines aus einer endlichen Menge von Symbolen interpretiert
    • Das ist ein Kompromiss, der für Menschen leicht zu zeichnen und für Computer leicht zu parsen ist

Funktionssymbole und Datenfluss über Drähte

  • Der Lambda-Kalkül kennt nur zwei grundlegende Operationen
    • Funktionsanwendung
    • Funktionsdefinition
  • λ-2D stellt die Funktionsanwendung als becherförmiges Symbol dar und die Funktionsdefinition mit dem griechischen Buchstaben λ
  • Wie im grundlegenden Lambda-Kalkül nimmt eine Funktion immer genau ein Argument an und erzeugt genau eine Ausgabe
  • Um mehrere Argumente zu verarbeiten, wird Currying verwendet, also das Verketten mehrerer Funktionen
  • Die Drähte zwischen den Symbolen dienen als Kanäle, durch die Daten fließen
  • Diese Sprachstufe ist technisch Turing-vollständig, in der Praxis aber sehr umständlich, weshalb zusätzliche Symbole wie Zahlen und mathematische Operatoren hinzukommen
    • Diese zusätzlichen Symbole sind syntaktischer Zucker
    • Wer möchte, kann auch nur reine Lambda-Kalkül-Strukturen wie Church-Zahlen verwenden

Frames, Zeichnungsdaten und Slider

  • λ-2D möchte die Erfahrung aus Scratch natürlicher erweitern, bei der man Sprites im selben Editor zeichnet und direkt verwendet
  • Frames funktionieren so, dass ein bestimmter Bereich der Leinwand mit Drähten umgeben und links oben mit einem Anzeigesymbol markiert wird
    • Kritzeleien innerhalb dieses Bereichs können als Daten verwendet werden
    • Die Form einer mathematischen Funktion kann direkt skizziert und etwa für Animationen genutzt werden
    • Formen werden als Daten behandelt, ohne dass man zuvor in einem separaten Schritt eine Gleichung finden muss
  • Außerdem wurden Slider eingeführt, die sich zur Laufzeit ziehen lassen
    • Sie dienen dazu, Programme parametrisch zu steuern
    • Künftig sind auch weitere GUI-Elemente denkbar

Editor und 5×5-Symbole

  • Die erste Idee entstand aus Beispielprogrammen, die von Hand auf punktiertes Papier gezeichnet wurden
  • Da der Computer-Vision-Teil zum Scannen von Programmen auf Papier noch nicht bereit war, wurde zunächst ein einfacher Editor gebaut, in dem Programme digital gezeichnet werden können
  • Jedes Symbol besteht aus 5×5 Pixeln, damit es sich leicht auf eine Gitterleinwand setzen lässt
  • Nutzer können wie mit einem Stiftwerkzeug auch frei von Hand zeichnen
  • Der anfangs nur als Zwischenlösung gedachte Editor entwickelt sich nach und nach zu einem Editor mit immer mehr Funktionen

Das Ausgabeproblem in einer rein funktionalen Sprache

  • λ-2D ist rein funktional und zustandslos, weshalb sich ein gewöhnliches print-Statement nur schwer umsetzen lässt
  • Ausgabe ist eine Zustandsänderung, und wenn man erwartet, dass in einer bestimmten Reihenfolge ausgegeben wird, setzt das auch eine Reihenfolge der Auswertung voraus
  • Der Lösungsansatz besteht darin, „Ausgabe“ funktional neu zu definieren
    • Einer Funktion wird eine leere Leinwand übergeben
    • Zurück kommt eine neue Leinwand, deren Pixel so verändert wurden, dass sie wie Text oder eine gewünschte Kritzelei aussieht
  • Die Sprache ist deshalb nicht um Strings und Zeichen herum entworfen, sondern um Leinwände und Pixel

JavaScript-Umwandlung und Visualisierung der Ausführung

  • Der grundlegende Parser wandelt ein komplettes λ-2D-Programm in einen äquivalenten JavaScript-Ausdruck um
  • Das resultierende JavaScript ist ein einzelner riesiger Ausdruck mit sehr vielen Klammern; ineffizient, aber funktionsfähig
  • Da der aktuelle Parser JavaScript ausgibt und die Ausführung der JavaScript-Engine des Browsers überlässt, lässt sich der eigentliche Ausführungsprozess nur schwer visualisieren
  • Stattdessen lässt sich der Parsing-Prozess leicht visualisieren und kann dem Pfad ähneln, den ein Tree-Walk-Interpreter beim Ausführen des Programms nimmt
  • Wenn man der Parsing-Animation symbolabhängige Klänge zuordnet, kann man die Programmausführung wie ein Lied „hören“
    • Das Ergebnis klingt eher wie ein seltsames Computerspiel aus der 8-Bit-Ära
    • Zu sehen ist das in der Online-Demo unter Menu > Program > Animated Run

Verbleibende Grenzen und nächste Schritte

  • λ-2D begann ursprünglich als Teil eines größeren Forschungsprojekts, in dem Programme mit Stift und Papier gezeichnet und per Augmented Reality interaktives Feedback gegeben werden sollte
  • Als das Projekt immer interessanter wurde, entwickelte es sich zu einem eigenständigen Projekt
  • Die ursprünglichen Ziele sind noch nicht vollständig erreicht
    • Programme neigen dazu, eher wie Schaltpläne als wie Zeichnungen auszusehen
    • Es ist schwer sicher zu sagen, ob die Sprache für gewöhnliche Menschen leicht zu erlernen ist
    • Auch für ein Computer-Vision-System ist es womöglich nicht einfach, sie fehlerfrei zu scannen
  • Nach weiterer Ausarbeitung von λ-2D sollen auch andere Programmiersprachen entworfen werden, die sich in Systeme integrieren lassen, welche Zeichnungen als Berechnung behandeln
  • Die Beta-Version von λ-2D kann online ausprobiert werden; der Quellcode von Parser und Editor soll in Kürze auf GitHub veröffentlicht werden

1 Kommentare

 
GN⁺ 2024-11-10
Hacker-News-Kommentare
  • Wenn einem so etwas gefällt, könnte auch die Arbeit als Automation Project Engineer interessant oder zumindest vertraut wirken.
    Function Block Diagrams (FBD) sind ziemlich ähnlich: Funktionsblöcke werden mit Linien verbunden, und die Ausführungsreihenfolge wird durch die Reihenfolge der Blöcke definiert. Die Blöcke selbst können so etwas wie eingebaute Funktionen der Engine sein oder zusammengesetzte Blöcke. Das Diagramm wird einmal pro Regelzyklus ausgeführt; normalerweise wird jeder Block, sofern es keine Jump-Blöcke gibt, in jedem Regelzyklus genau einmal ausgeführt, unabhängig davon, ob sich die Eingaben geändert haben.
    Steuerungslogik von Brauereien bis zu petrochemischen Anlagen wird auf diese Weise implementiert. Ich arbeite an der UI-Seite eines FBD-basierten Steuerungssystems und habe damit täglich zu tun.

    • Meinst du so etwas wie PLC, oder etwas Ähnliches?
  • Ähnlich wie BitGrid[1], aber nicht dasselbe. Man kann es sich als extrem vereinfachte Form eines FPGA vorstellen, bei der Bits parallel über ein Gitter marschieren.
    Diese Idee könnte eine enorme praktische Bedeutung haben – Petaflops für die breite Masse – oder auch nicht; letztlich hängt es davon ab, wie viel Energie ein einzelnes DFF in einem ASIC verbraucht. Die Zahlen, nach denen ich schon lange suche, sind die statische Leistungsaufnahme und die Energie zum Laden eines einzelnen Bits.
    Auch das Programmiermodell ist ein Problem. Niemand will Logik direkt auf einem Gitter platzieren; alle wollen so schnell wie möglich abstrahieren. Ich habe nicht genug Fokus, um diesen Teil hinzubekommen.
    Bei der Erkundung dieser Idee bin ich auf den Von-Neumann-Zellulären Automaten[2] und die Nobili-Zellulären Automaten[3] gestoßen, obwohl ich mich seit Jahrzehnten für ähnliche Ideen interessiere und sie zum ersten Mal gesehen habe. Dieser Bereich der Informatik ist frustrierend schwer auffindbar.
    Beide teilen dieselbe absurde Grundlage: Eine Menge von FSAs definiert einen unendlich großen Zellenraum, und alle FSAs haben dieselbe Zustandsübergangsfunktion bzw. dasselbe Regelwerk. Genau diese eine „Vereinfachung“ scheint das Ganze in den Bereich Code Golf zu drängen.
    [1] https://github.com/mikewarot/Bitgrid
    [2] https://en.wikipedia.org/wiki/Von_Neumann_cellular_automaton
    [3] https://en.wikipedia.org/wiki/Nobili_cellular_automata
    Falls jemand die BitGrid-Idee weiterverfolgen möchte, wäre ich dankbar.

  • Bei der Stelle „technisch gesehen ist die Sprache an diesem Punkt Turing-vollständig, aber extrem schmerzhaft zu benutzen und verstößt damit gegen meine Designregel Nr. 2“: Meine Lambda Diagrams[1] sind bei Stufe 1 stehen geblieben.
    Unten auf dieser Seite sind alle anderen mir bekannten grafischen Notationen für den Lambda-Kalkül verlinkt, und ich habe diese gerade ebenfalls hinzugefügt.
    [1] https://tromp.github.io/cl/diagrams.html

    • Auf dieser Seite könnte interessant sein: der Y-Kombinator als Lambda Diagram: https://tromp.github.io/img/cl/Y.logo.gif
    • Allerdings fragt die integrierte Übersetzungsfunktion von Firefox, ob sie diese Seite aus dem Griechischen übersetzen soll.
      Ziemlich coole Leistung, denn nun kann man behaupten, eine Sprache geschaffen zu haben, bei der der Browser sagt: „Für mich ist das alles Griechisch!“
    • Es ist auch extrem schwer zu lesen. Pixel-Fonts und Strichzeichnungen sind zwar nostalgisch, aber wenn man die Augen zusammenkneifen muss, um Buchstaben zu lesen oder Linienformen zu unterscheiden, ist das nicht ergonomisch.
      Solche Dinge hatten wir in den 90ern mit dem Aufkommen hochauflösender Displays eigentlich hinter uns gelassen.
    • Für mich sieht es aus wie sumerische Keilschrift, was cool ist.
    • Ich glaube, Alligator Eggs fehlt.
      https://worrydream.com/AlligatorEggs/
  • Solche Dinge hat man auch mit LabVIEW versucht, und man merkt, dass es schwer ist, damit sehr weit zu kommen. Auch Programme zur Klang-/Musikerzeugung haben das gemacht; Max [max] ist so etwas wie der Urvater davon.
    Man kann damit Dinge bauen, aber es wird schnell unordentlich. Ob es schön aussieht? Meiner Meinung nach nein.
    [max] https://en.wikipedia.org/wiki/Max_(software)

    • Das visuelle Leitungs-/Knoten-Paradigma von Max/MSP und Pure Data halte ich für ziemlich sinnvoll. Es baut auf der „eine Box in eine andere Box einstecken“-Schnittstelle elektronischer Musikhardware auf und kann auch das Layout elektronischer Schaltungen widerspiegeln.
      Komplexe Signalflüsse lassen sich in einem visuellen Layout, insbesondere in Diagrammen mit animierten Echtzeitwerten, viel leichter verfolgen als in statischen Textblöcken.
      In neueren Versionen von Max/MSP gibt es außerdem mc, das mehrkanalige Verbindungen bereitstellt, sodass man für mehrere identische Signale keine separaten Leitungen/Knoten erstellen muss; mit ~gen und JavaScript sind zudem textbasierte Programmierknoten möglich.
    • Sollte Simulink nicht auch auf diese Liste?
      Solche „Block-Programmiersprachen“ wirken vielversprechend, weil sie durch Blackboxing abstrahieren und Boxen innerhalb von Boxen erzeugen. Ich frage mich, ob die Implementierungen schlecht sind, ob sie falsch benutzt werden oder ob das Paradigma selbst nicht funktioniert.
      Zu bedenken ist, dass solche Dinge meist von Leuten verwendet werden, die Programmierung und Abstraktion nicht kennen. Wer gut programmieren kann, würde es vielleicht nicht unordentlich machen – aber dann kann man auch einfach Code schreiben, was die Sache etwas fragwürdig macht.
      Ich stimme zu, dass LabVIEW furchtbar ist. Nicht nur wegen dieses Problems: Updates machen alles kaputt, die Lizenzierung ist auch so ein Thema, und insgesamt ist es einfach ein Ärgernis.
    • Man kann durchaus sauberen und gut lesbaren LabVIEW-Code schreiben; es ist nur eine andere Denkweise.
      Es gab eine kleine Community professioneller LabVIEW-Entwickler, und sie haben im Allgemeinen sehr lesbaren und guten Code geschrieben. Anders als das, was den meisten vertraut ist, aber gut.
      Allerdings habe ich diese Welt vor ein paar Jahren verlassen. Es gab klare Anzeichen dafür, dass LabVIEW am Ende sterben würde, ganz gleich, was man damit machen kann.
  • Seit ich vor etwa 10 Jahren zum ersten Mal von Petri-Netzen gehört habe, interessiere ich mich für grafische formale Spezifikationen.
    Ich hatte immer das Gefühl, dass Ingenieure formale Methoden besser nutzen würden, wenn es statt einschüchternder mathematischer Notation und Sprachen grafische Darstellungen gäbe. Leider verloren andere Ingenieure fast sofort das Interesse, sobald ich ihnen Petri-Netze zeigte.
    Bevor ich mein Promotionsstudium an der University of York abbrach, arbeitete ich mit RoboChart und RoboSim[1]; ich denke, das könnte tatsächlich zugänglicher sein. Allerdings ist es ziemlich stark an Robotik-Semantik gebunden. Als persönliches Projekt habe ich versucht, RoboSim so anzupassen und zu erweitern, dass es für die Welt von Netzwerken und Servern nützlicher wird.
    [1] https://robostar.cs.york.ac.uk/robotool/

  • Das gefällt mir wirklich sehr. Besonders, dass es in JavaScript implementiert ist.
    Puristen werden sich im Bett oder im Grab umdrehen, aber zumindest dürfte das Visualisierungs- und Audio-Follow-up dadurch deutlich einfacher geworden sein. Die Visuals sind großartig, und der nächste Schritt scheint zu sein, die übergeordnete Struktur bestehender Programme irgendwie in dieses Format zu übersetzen. Es dürfte einige Nerds geben, die dafür bezahlen würden, sich den Dijkstra-Algorithmus oder den Backpropagation-Algorithmus eines künstlichen neuronalen Netzes an die Wand zu hängen.
    Interessant fand ich die Stelle, dass die Sprache so rein funktional und vollständig zustandslos ist, dass sich keine print-Anweisung implementieren lässt. Ausgabe verändert nämlich Zustand, und zu erwarten, dass etwas in einer bestimmten Reihenfolge ausgegeben wird, bedeutet anzunehmen, dass Ausdrücke in einer bestimmten Reihenfolge ausgewertet werden.
    Heißt das nicht einfach nur „nicht imperativ“? Trotzdem würde mich interessieren, wie man Zustand kodieren würde. Vielleicht könnte man Variablen einführen, etwa Icon+Farbe, und einzelne Anweisungen entlang einer Achse oder beider Achsen ausrichten.

  • „Der Bereich nichtsprachlicher Programmiersprachen ist nicht unerforscht“
    Schon ab dem zweiten Satz geht es mit einer aggressiven dreifachen Verneinung los.

    • Und gibt es nicht auch Scratch?
  • Das erinnert mich an Wireworld von 1987. Natürlich gibt es dazu auch einen Wikipedia-Artikel [1].
    Ich habe einmal einen in Wireworld implementierten 8-Bit-Zähler gesehen, und der war ziemlich beeindruckend. Das hier wirkt allerdings etwas knapper.
    [1]: https://en.wikipedia.org/wiki/Wireworld

    • Mir gefällt irgendwie deutlich besser, wie Zachtronics es in KOHCTPYKTOP umgesetzt hat.
      Allerdings ist es heute schwer zu spielen, weil die Webseite[1] und die Steam-Version von Flash abhingen und man mit Flash-Reimplementierungen von Drittanbietern herumhantieren muss.
      Trotzdem finde ich die Implementierung des Halbleiterverhaltens viel besser als bei Wireworld.
      [1] https://www.zachtronics.com/kohctpyktop-engineer-of-the-peop...
  • Direkter Link zur Online-Demo: https://l-2d.glitch.me/

    • Den Kern haben sie ziemlich tief vergraben.
  • Das sind weitere sehr visuelle Programmierumgebungen/-sprachen, die ich gefunden habe. Sie unterscheiden sich von anderer visueller Programmierung, bei der man Knoten mit Linien verbindet.
    Man könnte sie anders klassifizieren, aber ich weiß nicht, wie man das nennen sollte.
    Piet https://www.dangermouse.net/esoteric/piet.html
    Turnstyle https://jaspervdj.be/turnstyle/ https://github.com/jaspervdj/turnstyle
    Markovjunior https://github.com/mxgmn/MarkovJunior
    Cellpond https://cellpond.cool/ https://github.com/TodePond/CellPond https://www.youtube.com/watch?v=xvlsJ3FqNYU
    Imagegram https://zaratustra.itch.io/imagegram
    Color Code http://colorcode.bananabanana.me/ https://www.youtube.com/watch?v=5M5hy9xsqKc Color Code 2 http://colorcode2.bananabanana.me/ https://www.youtube.com/watch?v=tTvvX4sjZWw Splaty Code http://splatycode.bananabanana.me/ https://www.youtube.com/watch?v=gd_e85lAKOs (erstellt von Muril Polese https://github.com/murilopolese/ http://gallery.bananabanana.me/)
    Alchemy Online https://maxbittker.github.io/alchemy-online/ https://github.com/MaxBittker/alchemy-online