 sehr, dass ich Nikola Projá vorstellen kann, der ein Post-Talk-Forscher an der Universität in Gruppenhagen war. Ich bin sehr stolz, dass er hier ist. Er arbeitete für ein Projekt im ICU. Er war im Forschungsprojekt, die sich auf das Design von Programmiersprachen konzentrierte und mit der Programmierung. Heute wird Nikola ein Vortrag halten über eine experimentelle Sprache mit dem Namen Link, hergestellt in Zusammenarbeit im Kooperationischen ICU Hagen. Bitte herzlich, dass wir kommen für Nikola Polar. Vielen Dank. Ich bin sehr froh, hier zu sein heute, um diese neue Programmiersprache vorzustellen, an der ich gearbeitet habe für die letzten Monate, die aus einer vorherigen Forschung entstanden ist. Programmiersprachdesign ist etwas, was mir sehr liegt. Hier möchte ich einen speziellen Fall adressieren, wo es nicht ausreicht, eine funktionale Sprache zu haben, wo einfach der modulare Anspruch die notwendige Präzision vermissen lässt. Sprechen wir über Optimisierung. Optimierung eines Programmes kann manuell geschehen oder vom Compiler gemacht werden. Optimisierung sollen das Programm verbessern. Das ist allerdings sehr schwer zu garantieren, weil Systeme heutzutage sehr komplex sind. Es könnte sein, dass du ein paar Zeilen beseitigst und trotzdem kann das Prungaufhaber langsam sein. Ausnehmen sollte Optimisierung irgendwie sicher sein und sollte nicht, es gibt viel zu viel schlechte Programmierung und wenn dann auch noch Compileroptimierung dazu kommt, das wäre schlecht. Vieles an Optimierung wird automatisch vom Compiler vorgenommen. Wenn es automatisch vorgenommen wird, wenn das so ist, sollte es vorherrsagbar sein, was es tut und wann es das tut. Nehmen wir mal einen generellen Fall von Optimisierung. Nehmen wir mal an, wir haben zwei Teile eines Programms. F und G. F liest ein paar Daten und G liest es wiederum und produziert ein paar Daten zur Ausgabe. In einigen und sogar in vielen Fällen. Und es ist dann so, dass beide Teile zu einer Funktion zusammengeführt werden könnten, zu einer Funktion FG, die dann die Daten ein liest und ausgibt und sie alluziert dann nicht die Zwischendaten. Das geht nicht immer. Der Vorteil ist allerdings, das tut denn das, was es soll, dann wann es das soll, was man jetzt tun kann. Man kann jetzt F zum Beispiel verbessern, wenn man das getrennt hat, um jetzt eine bessere Daten zu produzieren oder man kann G in einen besseren Datenverbraucher umwandeln. Jetzt die Frage, was passiert, wenn der Compiler das optimiert. Der kritische Bereich dieser Art von Optimierung, diese Optimierung werden von Hand normalerweise gemacht. Numerische Berechnungen, Embedded Systems, Treiber und Kernelmodule und außerdem, was mir wichtig ist, Security und Kryptografie. Wir wollen zwar garantieren, dass die Programme schnell sind, wir wollen aber auch, dass die Programme unabhängig von den Daten gut funktionieren, damit wir Timing Side-Channels vermeiden können. Was haben wir jetzt also hier? Wir haben hier Begriffe. Wir wollen jetzt darüber nicht zu viel sprechen. Wir brauchen Metaprogrammierung. Wir können etwas bessere Sachen sprechen, als über CPP oder wir sprechen auch über Daten. Wir sprechen über, worüber wir viel sprechen. Es sind Prozesse, die wir benutzen, um das Verhalten von Datenlesern und B schreiben. Also wir wollen nicht einen Int und einen Boolean oder ein Array miteinander vermischen. Sessions sind die Typen für Prozesse und die sind da, um durchzusetzen, dass wir das verhalten wollen, dass wir wollen. Wenn wir also zum Beispiel sagen, dass wir einen Int lesen wollen, dann sollten wir nicht etwas anderes schreiben. Wir haben abhängige Typen und Sessions, die wir jetzt nicht besprechen werden, weil das ein anderes sehr großes Thema ist. Aber entscheidend ist, dass wir, dass das bereits in der Sprache enthalten ist, denn dadurch bekommen wir formale Verifizierung und das auf einem einfachen Wege. Und am Schluss aber nicht als Letztes. Wir haben duale Sessions, die eine Optimierung möglich machen, die ich vorher gesprochen habe. Okay, wo kommt diese Sprache her? Ich habe mich durch mehrere Sprachen inspirieren lassen von funktionalen Sprachen wie Haskell, auch vollentwickelte Entwickelsprachen für Programmieren wie Cog, Agda und Idris. Ihr kennt vielleicht aus Erlang oder den P-Kalkül besser. Das ist etwas, was ich ex-Wähler hatte und die Forschung über Session Types und lineare Logik. Da gibt es viele Forschungspapiere und ich und Kollege bei der IT-Universität Kuppenhagen. Also, ließ es nicht gut. Dies sollte eine schöne Zusammen-eine Summierung sein. Okay, das ist nur der eine Fall. Also, nehmen wir ein Beispiel mit Matrix-Multikation. Wir haben zwei Matrizen A und B und die wollen wir multiplizieren. Was wir wissen ist, dass, oh, dies ist nicht gut. Jemand hat es mir, hat mich gewarnt. Okay, das ist nicht so ein großes Problem, glaube ich. Wir haben also eine Zeile in A und eine Spalte in B und diese beiden Vektoren müssen die gleichen Länge haben, die gleiche Größe haben und wir werden jetzt mit der Multiplexion einen einzigen Vektor erhalten. Und die funktionale Repräsentation, die wir hier nicht wirklich sehen, ist, wir bauen diesen Vektor, der die Multiplikation ist und summieren das gleich auf. Wir bilden dies für Modularität auf. Am Ende sollten wir eine Lage sein, dieses Programm so zu schreiben, dass wir diesen Temperaturen-Vektor adoptieren können und er dann von selbst wieder verschwindet. Wir sehen hier ein erstes Link-Programm und sprechen dann über Typen und die Rolle als Approximations-Tool und dann reden wir über Fusion, Allocation und Fusion. Das ist die Optimierung von vorher und dann wieder zurück zur Matrix-Multiplikation. Also, hier ist das erste Programm. Es heißt, wir haben zwei Kanäle, A und B, und diese Kanäle haben eine Session. Das kann dieses Fragezeichen sein oder Ausrufungszeichen sein. Das Fragezeichen heißt Lesen, das Aufrufungszeichen heißt Schreiben. Wir müssen also einen Int lesen auf A, was wir mit diesem Let und der Pfeilsyntax bekommen und haben dann in X diesen Wert und der Punkt weist auf die Sequenz hin und dann machen wir einen Schreibvorgang auf B und schreiben dort x plus x. Das Typsystem der Sprache stellt sicher, dass wir einen einzelnen Lesenvorgang oder einen einzelnen Schreibvorgang auf diesen Kanälen bekommen. Machen wir nun einen weiteren Prozess, der 21 als Eingabewert bekommt. Ein neuen Prozess, der mit einem einzelnen Kanal, auf dem wir einen Int auf B schreiben und wir holen uns nun einen Kanal A, schreiben 21 nach A und können dann unser Double-Programm mit A und B aufrufen und schaut euch nun das Gleichheitszeichen an. Das heißt, es gibt eine Definition. Das bedeutet, wir können immer Double mit der Definition ersetzen. Wir können jetzt also ein Programm erhalten, das die Definition von Double einsetzt. Hier sehen wir also die die Zuweisung, die Alluzierung, die Zuweisung, wenn wir das schreiben und dieses Einfall in dem Fusion angewendet werden kann, um diesen Vorgang von Alluzieren, Lesen und Schreiben durch einen Vorgang ersetzen kann und dies passiert auf dem statischen Niveau. Das wird expandiert und gibt uns dann dieses zweite Programm, das einfach direkt 42 schreibt. Mit diesem einfachen Programm sehen hier die Deklarationen von Prozessen, das Belegen, das Alluzieren von Objekten und das Lesen und das Schreiben. Sprechen wir nun über Typen, Typsysteme. Wenn ihr glaubt, dass Typen-Systeme hier einfach nur dazu sind, vielleicht denkt ihr, dass Typen-Systeme nur dazu sind, um Programme zurückzuweisen oder das Java, C-Sharp oder C++ ein gutes Typen-System haben, vielleicht bevorzugt ihr aber auch ein dynamisches Typen-System und sagt, dass das ein Typen-System durch Unitests einfach ersetzt werden kann und in all diesen Fällen würde ich sagen, ihr ehrt euch, denkt nochmal nach. Ich denke ein gutes Typen-System sollte etwas Positives sein. Es sollte erklären, warum und wo ein Programm fehlschlagen kann, scheitern kann und wo es das tun wird und es kann den Compiler für Optimierung in Hinweise geben und ihn dazu befähigen und es ist entscheidend, dass wir die richtigen Typen bekommen, um dies zu ermöglichen. Ein weiteres Beispiel ist, dass wir manchmal Typen so genau entwerfen können, dass das Programm automatisiert wird. Es gibt dann eventuell gar nicht mehr den Bedarf, ein Programm zu schreiben. Also erinnern wir uns vor allem an dies. Ein Typ ist eine Approximation und die hat insbesondere den Zweck, um Abstraktion zuzulassen. Ein Int ist eine Approximierung für fünf und sieben zum Beispiel. Ein Integer, der ungerade ist, würde ein genauerer Typ sein oder ein Integer, der eine Primizeil ist, wäre ein genauerer Typ oder ein Integer, der gleich fünf ist, wäre ein genauerer Typ. Es gibt also einen großen Bereich von möglichen Approximationen, die wir als Typen verwenden können. Also Typen sind hier für die Daten und Sessions sind für das Verhalten. Wenn wir also uns anschauen, was Approximation heißt, nehmen wir ein weiteres Beispiel. Wir haben ein Prozess, Diff Mode, der zwei Inputs liest, A und B und der dann zwei Werte rausschreibt, nämlich D, das ist A geteilt durch B und M, den Rest beim Teilen von A durch B. Das ist also ein Prozess und wir können sehen, dass der parallel und sequenzial kombiniert werden kann. Wir können jetzt also einen Typ, eine Session diesen Prozess geben und bekommen dadurch eine Möglichkeit, ein genaues Interface zu definieren für den Prozess. Außerdem erinnert euch, dass in der ganze Zeit diese Kanäle genau einmal nur verwendet werden können. Okay, also diese Folie ist ein bisschen beängstigend. Ich habe hier sechs Programme, sechs Versionen des Programms zur gleichen Zeit und fünf Versionen des Typen. Wir können uns das also einige davon uns anschauen. Der Typ ist in Grün. Dies ist das erste Programm, das dieses Lesen und Schreiben sequenziell durchführt. Diese mit diesem Pipe Symbol sagt, dass wir diese Dinge parallel tun. Diese zwei Vorgänge werden parallel ausgeführt, die Lese und die Schreibvorgänge. Also wir haben also etwas sequenziales und etwas paralleles Verhalten hier und all diese Dinge werden akzeptiert innerhalb dieses selben Typen. Das Wittes sagt, dass wir ein A und ein B lesen sollen und ein D und ein M schreiben sollen. Schaut euch diese geschweiften Klammern an. Das sagt euch, dass ihr eine Wahl habt über die Reihenfolge. Also all diese Dinge sind deshalb gültig. Wir könnten jetzt also genauer sein über die Art von Prozessen, die man versucht. Wir haben jetzt hier in dieser recht, in dieser quadratischen Spalte. Wir haben hier ein Programm, das sequenzielle Ausführung erzwingt und dadurch bekommen wir sehr schnell die Garantie, dass es gültig ist. Okay, wir könnten sagen, dass wir all diese Kanäle parallel benutzen wollen und unabhängig voneinander benutzen wollen, außer naja es wird nicht wirklich sinnvoll sein, denn wir müssen die Division und die Restberechnung können wir nicht schreiben, ohne Zugriff auf die Werte zu haben. Wir könnten aber auch etwas genauer, etwas feiner das Ganze definieren. Wir könnten die akkigen Klammern hier benutzen und die geschweiften Klammern um zu sagen, dass wir zunächst die Lesevorgänge und dann die Schreibvorgänge parallel halten wollen, sodass nur dieses mittlere Programm gültig ist. Wir können Variationen haben. Was wir also bekommen sollten hier ist, erinnert euch zumindest an diese verschiedenen Möglichkeiten, die wir haben, diese Auswahlmöglichkeiten. Okay, Dualität. Wären wir also an dieser Kanäle denken, denken wir daran, das sei Speicher, oder bewerten wir das als ein Protokoll. Ich schreibe einen Integer, dann sollte der Typ, der das Gegend um sollte, auch ein Integer sein. Diese Dualität betrifft zum Beispiel tupelt oder erase, also wenn die eine Seite also die Reihenfolge der Prozesse bestimmen kann, dann hat die andere Seite keine Wahl. Wenn wir jetzt die, es haben, wenn wir das andere minus haben, dann haben wir das andere, wenn wir hier Klammern haben, dann je nach Klammertüber ist es eine sehr strikte oder eine freie Reihenfolge, der es ausgeführt wird. Die eine Klammer ist von links nach rechts und wenn wir jetzt Klammern mit Stoppepunkten haben, wir Serialisierung von links nach rechts. Jetzt haben wir hier ein PR von Integer und dann ein weiteres Paar von Double und Interstellvariablen. Mit dem Zeichen können wir bestimmt über die Klammern in welcher Reihenfolge stattfindet. Wir wollen halt zum Beispiel erst ein Double und ein Int entgegennehmen und dann ein weiteres Int. Wenn wir jetzt auch ein Tilde Zeichen hinzuführen, dann geht es schnell. Dann werden die Ausführungszeichen Fragezeichen und die Fragezeichen werden Ausführungszeichen. Das Ergebnis ist, dass der entgegengesetzte Prozess einen Int erhalten muss, unabhängig von davon, dass dieser Double hier geschrieben wird in dieser Reihenfolge. Insbesondere kann er kein Int lesen und dann ihn zurück senden. Dies würde einen Deadlock auslösen, eine Blockade. Also mit dieser Nebenläufigkeits-Einstellung haben wir die Möglichkeit, Blockaden zu vermeiden. Also Zuteilung mit Fusion, Allokation mit Fusion. Nehmen wir uns mal dieses einfache Setting, wo wir zwei Prozesse F und G haben, die etwas Duales ausführen, zueinander Duales. Das könnte irgendeine Session sein und dann das Dual davon. Mit diesen neuen Syntax, die diese Eckenklammern hinzufügt, die euch sagen, dass das ganze Parallel ausgeführt werden muss, dies erfordert, dass das C und D parallel benutzt werden. Dies ist der Fall, wenn Fusion in allen Fällen, wo man diese beiden Teilen des Programms als Dual voneinander ausdrücken kann, dann weiß man, dass man die Allokation wieder entfernen kann. Aber vielleicht möchte man die Parallelität nicht haben. Wir haben also diese andere Syntax wieder mit derselben Anforderung, aber jetzt mit sequenzueller Bearbeitung. Dies ist etwas mehr beschränkt, weil wir jetzt alles, was wir vorher mit C tun, vor dem Behandeln von D tun müssen. Wir haben also eine Zuteilung von Speicher, die hier nicht zusammengefügt werden kann. Wir haben hier ein Beispiel, das also in beide mit geschweiften Klammern und wir haben hier eine neue Notation mit dem Dach. Das bedeutet, dass diese Tupel, hier werden zwei Ins geschrieben in einer Reihenfolge, die wir nicht wissen, vielleicht von links nach rechts. Und dieser andere Prozess möchte diese 100 Ins lesen in einer vielleicht anderen Reihenfolge. Wenn wir F und G nicht ändern, dann haben wir keine Wahl. Wir haben jetzt unbestimmte Daten, die zugeteilt werden. Und dann F wird all diese Orte in der Reihenfolge schreiben, die es mag. Und G wird alle Lesen in der Reihenfolge, die es mag. Dies ist also ein Fall, wo, wenn man nicht das Allokfly hinzufügt, wird das New sich beschweren und sagen, ich kann das nicht verwenden, so in der Form, es muss allokiert werden. Und wenn man das nicht möchte, dann kann man F ändern und mit F sagen, ja, es könnte, man kann ein bisschen mehr arbeiten und diese 100 in Titras parallel schreiben. Wenn man dies tut, dann wird das nicht fusioniert. Wir haben jetzt die Zuteilung, wir können jetzt zurückgehen zur Matrix-Multipikation. Ich werde jetzt nicht ins Detail gehen bei diesen Operationen. Aber was wir hier bekommen ist, wir schreiben eine SIP-Funktion und leiten die ab von einer sehr viel allgemeineren Funktion, die nicht nur für Doubles und nicht nur für Multifikation funktioniert, sondern für alle möglichen Typen mit einer Operation F. Und wir können das nun so kurz schreiben wie das hier. Diese Summation könnte auch vorgenommen werden mit. In funktioneller Programmierung bevorzügen wir eigentlich eher. Ich überspringe wieder das Detail, aber ihr seht hier, dass eine temporäre Variable benutzt wird, um das Ergebnis von F zu akkumulieren, was jetzt in diesem Fall die Edition von Doubles wird. Jetzt können wir also zusammenfügen die SIP-Funktion und die andere Funktion und haben dann diese Zwischendaten, die uns theoretisch sagen, dass wir sie mit Fuse wegoptimieren können. Also eine fusionierte Version ist dies hier, wo wir sehen, dass die Summierung gemischt wird mit dem Null und dem Plus mit der Multiplikation in einer einzigen Funktion. Ja, also irgendeine Art von Schlussfolgerung. Wir können hier Präzision, Genauigkeit und Modularität kombinieren und haben eine kostenlose Abstraktion. Und das ist ziemlich allgemein, das enthält. Es ist vorherrsagbar, es ist sicher, es ist automatisch. Wir haben also das umsonst. Es ist Sprache und die Werkzeuge sind komplett Open Source und ich hoffe, ihr werdet euch das anschauen, probiert das aus, tragt vielleicht etwas bei. Jetzt stell Fragen, berichtet, vielen Dank. Okay, Fragen? Fangen hier mit den Mikrofonen dort an. Ist es possible to use this language, for example, to synthesize the logic or a sequence logic, maybe a clockless logic in an a chip? I'm not sure I got the question. To use it for what? Synthesizing logic to actually do your computation in hardware. Kann man das nutzen, um die, mit dieser Sprache Berechnung in Hardware vorzunehmen? Ja, also diese Sprache und die Werkzeuge sind wirklich neu. Also es gibt immer noch viele Bugs, nicht ganz implementierte Features, aber theoretisch ist es sicherlich möglich, dies zu tun. Wir haben hier einen abstrakten, einen hochsprachigen Weg, um diese Dinge aufzuschreiben, aber die Hauptdomäne ist Institutionen, in denen Performance wirklich entscheidend ist. Also vielleicht ist das hier der Fall, ich weiß sonst, vielleicht ist Haske sonst gut genug. Okay, one question over here, please. Ich fragte mich über verschiedene Schreibweisen, von der ich mich über verschiedene Schreibweisen, über die Reihenfolge, wie man etwas realisieren kann oder so. Ich kann nicht das meiste vom Contailer eigentlich auch vorhergesagt werden, wenn ich den Flow nur vorher beschrieben habe. Was jetzt sechs verschiedene Warten beschrieben? Also im ersten Schritt in Typsystem ist es immer einfacher zu prüfen, dass die Typen korrekt sind, anstatt zu raten oder zu erschließen, was die Typen sind. Und das ist nicht immer das, was man will, aber es ist wahr, wir könnten hier erschließen, was Typen sind, ja, einige Typen, ziemlich viele. Also der Typchecker, der auf Prozessen arbeitet, ist tatsächlich bottom up, startet von den Blättern des Programms und überprüft dann der Typ und überprüft, dass er mit der Definition zusammenpasst. Aber es ist wichtig einen Weg zu haben, nicht den allerpräzisisten Typen anzugeben, ein bisschen Spielraum zu haben, wenn man definiert etwas, was mehr approximativ ist, damit man sagen kann, okay, ich kann jetzt die Reihenfolge vertauschen oder links nach rechts zunächst einmal. Also kann ich also einen Prozess erzeugen, der zum Beispiel eine Initiative pro Zeit produziert und so, dass ich die dann alle beim Consumer irgendwas dann noch rein vorgelesen muss. Ja, vielleicht, also eine Sache, die wir nicht wirklich tun können zu diesem Zeitpunkt, ist ein Prozess zu haben, der parametrisiert ist, bezüglich der Ausführungsreihenfolge, die wir haben. Man kann den Kot nicht parametrisch aufschreiben, das ist kein Dialog, bitte mehr Fragen auf der anderen Seite. Danke für den Vortrag, sehr interessant. Ich fragte mich, kommt eine Dataflusssprache als Idee vor, so eine Art? Ja, also Funktionalesprogrammieren ist schon Datenfluss in vieler Hinsicht. Typischerweise ist Funktionales Programmieren ein Erfolg in vieler Atmosphäre, aber es scheitert daran, genau genug zu sein, über die Frage, wann eine Speicherzustellen gemacht wird. Und das ist das, was ich hier versuche zu lösen. Wir wissen, dass normalerweise bei Fat-Pay-Default Also wenn es fehlschlägt, sieht man wenigstens genau, wo das Problem auftaucht und man kann dann überlegen, was man ändert und einen Weg zu euch kasseln, um das tatsächlich zum funktionieren zu bringen. Eine weitere Frage dort, bitte. Produziert Link Compiler schon ausführbare Programme? Ja, also wir sind jetzt in meinem frühen Zustand, aber er produziert C-Code zum Beispiel. Und das C-Backend ist, es gibt einige Operationen, die derselben Sprache bleiben und letztes Endergebnis ist dann das C-Backend ist noch nicht komplett vollständig, nicht optimal, aber es produziert genauen Code und das ist, also es ist nicht undenkbar, dass man hier bare Metal Code schreibt. Ich habe mir den Code angeschaut auf dem Radio Badge und ich habe einen Beispiel vom Matrix-Medikation gefunden. Ich habe also diesen Code, den Code von Link nach C übersetzt und habe ihn auf das Device gebracht und vielleicht kann man, wenn man vielleicht die Kamera sieht, dann kann man vielleicht die Animation sehen, wenn das die Kamera ändern könnte. Okay, noch eine weitere Frage auf der Seite, bitte. Du sagst also, dass Link abhängige Typen hatte, die sich aus den auf lineare Typen, könntest du bitte noch ausführen? Ja, also machen wir mal den Unterscheidungen zwischen dem, was mit dem Typsystem gemacht werden kann, was kann ich überprüfen und was kann ich übersetzen in C oder anderen Code. Was kann ich prüfen? Das ist tatsächlich, dass wir dependent Typen oder abhängige Sessions haben. Ich kann sagen, dass ich einen Endempfangerex und wenn dieses X dann unter 10 ist, dann sollte ich einen Bullien empfangen oder sonst etwas anderes. Also das Protokoll kann abhängen von den eigentlichen Daten. Wir können außerdem wieder beim Prüfen Prozesse senden, Sessions senden empfangen, alles was einen Typ haben kann. Okay, wir haben noch Zeit für eine weitere Frage aus dem Internet. Noch eine Frage aus dem Internet. Ah, das Internet ist still. Dann noch die letzte Frage heute Abend. Wenn du drüber nachgedacht hast, als du drüber nachdacht hast, die Sprache zänfigen, hast du versucht, irgendwie eine Imlimitation anstatt das zu erzeugen, die als Bibliothek funktioniert oder als Erweiterung für eine weitere Sprache. Die abhängigen Typen sind eine Erweiterung. Es wäre interessant, dass zum Beispiel alles in Haskell zu integrieren. Das Hauptproblem ist das Handeln von Session und die Linearität. So etwas als eingefügte DSL-Zentwicklung ist schwierig. Das ist ein, hört sich nach einem Featureprojekt an. Das schien mir sinniger, eine neue Sprache zu erzeugen, aber ich stimme zu. Das könnte auch ein großes Projekt geben, das in die Sprache Haskell zu integrieren. Danke, einen herzlichen Applaus für der Prodiat.