Bester syntax für mehrzeilige lambdas?

Python in C/C++ embedden, C-Module, ctypes, Cython, SWIG, SIP etc sind hier richtig.
Antworten
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

Ich baue aus Spaß an der Freude gerade einen top-down Parser in Python. Die Sprache, die dieser Parser interpretiert, ist an Python angelehnt (Blöcke werden durch Einrückung angezeigt). Das funktioniert auch schon alles wunderbar, allerdings möchte ich, wenn ich schon einmal dabei bin, auch ein paar Verschlimmbesserungen ein bauen.

Aktuelles Projekt: "Function definitions as expressions."
Im Klartext heißt das: Ich will mehrzeilige Lambdas. Guido hat dazu mal gesagt, das es technisch möglich aber für seinen Geschmack zu umständlich sei. ich will das aber trotzdem. Darum! ;)

Mein momentaner Stand ist dieser:

Regel: Die erste nicht-leere Zeile eines Blocks gilt als Referenz für die Einrückung des gesamten Blocks. Ein Block endet vor der ersten nicht-leeren Zeile, die weniger Eingerückt ist als die Referenz-Zeile, oder vor einer schließenden Klammer, die nicht innerhalb des Blockes geöffnet wurde, oder am Ende der Datei.
Beginnt ein Block nicht mit einem NEWLINE, endet der Block nach genau einem Ausdruck. Das sind dann single-line Lambdas. Wie bei Python wird der Wert des Ausdrucks zurück gegeben, als ob davor ein "return" stünde.

Beispiele::

Code: Alles auswählen

    func = def(a, b):
        return a+b

    func = def(a, b): a+b

    map(iterable, def(s):
        return s.upper())

    list_of_functions = [
        def(a):
            return a*2
        , def(b):
            return b*4
        , def(c): c*8
    ] 
Jetzt meine Fragen: Sind die regeln ausreichend? Gibt es eventuell Mehrdeutigkeiten, die ich übersehen habe? Würdet ihr das anders lösen?
Bottle: Micro Web Framework + Development Blog
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Defnull: ich halte die Unterscheidung zwischen def-Einzeilig und def-Mehrzeilig für unschön. Einmal braucht man ein return, das andere mal nicht. Der Nutzen ist auch eher begrenzt, dafür dass die Syntax im einiges komplizierter wird. Mehrzeilige Lambdas werden schnell unübersichtlich, wenn sie als Argument irgendwo auftreten. Dann würde man das Argument doch wieder vor den Funktionsaufruf ziehen und hat keinen Unterschied mehr (def bla(...) zu bla=def(...).
Wie sieht denn das mit der Einrückung aus: Innerhalb von ( und ) ist die Einrückung egal, wenn zwischen den Klammern ein def steht aber wieder nicht.
Benutzeravatar
diesch
User
Beiträge: 80
Registriert: Dienstag 14. April 2009, 13:36
Wohnort: Brandenburg a.d. Havel
Kontaktdaten:

  • Die Bezeichnung "single-line Lambda" ist irrerführend, da ein "single-line Lambda" einen mehrzeiligen Ausdruck enthalten kann
  • Ich halte die unterschiedliche Angabe des Rückgabe-Werts bei ein- und mehrzeiligen "def"s auch für unschön und würde darauf verzichten.
  • Wenn deine Funktionsdefinitionen Ausdrücke sind, ist

    Code: Alles auswählen

    def f(i): return i+1
    eigentlich nur eine Abkürzung für

    Code: Alles auswählen

    f = def(i): return i+1
    Du könntest dann auch auf benannte Funktionen komplett verzichten.
http://www.florian-diesch.de
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

Mit dem impliziten "return" habt ihr wohl recht. Lieber explizit statt implizit.

Ich hab gestern und heute den Kram mit den Einrückungen implementiert. Mein Lexer zählt nun die Whitespace-Zeichen am Anfang jeder Zeile und hängt die Info an jedem Token der besagten Zeile. So kann der Parser ganz gut darauf zu greifen. Trotzdem wäre ein "end" keyword oder die klassischen geschweiften Klammern um einiges einfacher zu implementieren gewesen. Egal, mein Parser kann jetzt beides.

Hier mal ein kleines Test-Script und der dazu gehörige AST:

Code: Alles auswählen

a = (5 + 6) * 7 + 8 ** 9 ** 10
block:
    x = "Hello "
    y = "World\\n"
    return x + y
l = [1,2,3]

Code: Alles auswählen

set(a, add(mul(add(5, 6), 7), pow(8, pow(9, 10))));
block(set(x, 'Hello '), set(y, 'World\n'), return(add(x, y)));
set(l, [1, 2, 3]);
Das Beispiel ist jetzt noch recht einfach, was die Blöcke an geht. Hier mal was komplizierteres:

Code: Alles auswählen

list_of_blocks = [
    block: return 5
    block:
        return 6
    , block:
        return 7]

Code: Alles auswählen

set(list_of_blocks, [block(return(5)), block(return(6)), block(return(7))]);
Bottle: Micro Web Framework + Development Blog
Antworten