Ist eine doppelte Syntax zum Definieren benannter Funktionen eine schlechte Entscheidung für das Sprachdesign?

9

Ich modelliere eine Programmiersprache zum Spaß und die Syntax wird stark von Scala-spezifischen Funktionsdefinitionen beeinflusst.

Ich bin auf ein Entwurfsproblem gestoßen, weil meine Sprache nicht zwischen Funktionen unterscheidet, die über die defSyntax (Klassenmethoden) definiert wurden, und anonymen Funktionen, die Werten zugewiesen wurden (erstellt mit =>) - sie beseitigt die Unterschiede sowohl in der Implementierung als auch im Verhalten .

Das Ergebnis ist, dass die folgenden zwei Definitionen dasselbe bedeuten:

def square(x: Int) = x*x

val square = (x: Int) => x*x

Es gibt keinen Grund, das letztere Formular (sofortige anonyme Funktionszuweisung) in einer normalen Situation zu verwenden - es ist einfach möglich , es anstelle des defFormulars zu verwenden.

Würde eine solche doppelte Syntax zum Definieren benannter Funktionen die Orthogonalität der Sprache oder einen anderen Designaspekt beeinträchtigen?

Ich bevorzuge diese Lösung, weil sie kurze und intuitive Definitionen von Methoden und benannten Funktionen (via def) sowie kurze Definitionen anonymer Funktionen (using =>) ermöglicht.

Edit: Scala tut Unterscheidung der beiden - anonyme Funktionen sind nicht das gleiche wie Methoden definiert mit defin Scala. Die Unterschiede sind jedoch relativ subtil - siehe die Beiträge, die ich zuvor verlinkt habe.

jcora
quelle
However, assigning existing functionsscheint das Ende des Satzes zu fehlen
Izkata
1
Können Sie rekursive Funktionen mit Ihrer valNotation definieren?
Giorgio
2
Ich habe überprüft, dass dies auch in Scala möglich ist. In SML ist dies nicht der Fall und Sie müssen funeine rekursive Funktion definieren.
Giorgio
3
Die zweite Form ist eigentlich keine spezielle syntaktische Struktur def. Es ist nur ein Nebeneffekt der Tatsache, dass eine anonyme Funktion, (x : Int) => x + 1beispielsweise ein Objekt, ist und Objekte Werten mit zugewiesen werden können val f = .... Die Sprachdesigner hätten auf den Weg zu gehen , um die Syntax zu verbieten. Es ist nicht ganz dasselbe, als sich explizit darum zu bemühen, zwei verschiedene Syntaxen zu unterstützen, die (ungefähr) dasselbe tun.
KChaloux
3
Der Hauptvorteil von etwas mehr als einer Art in einer Sprache ist, dass es eine großartige Möglichkeit ist, unproduktive religiöse Debatten zu beginnen, die von den wirklichen Problemen ablenken (C ++ hier denken) .......
mattnz

Antworten:

3

Ich denke, dass zwei Konstrukte, die dasselbe bedeuten, aber unterschiedlich aussehen, in einer Sprache auf ein Minimum beschränkt werden sollten. Jede Vervielfältigung erhöht die Schwierigkeit, Ihre Sprache zu lesen (und damit Code zu schreiben / zu ändern). Das Eliminieren jeglicher Duplizierung ist in einer Sprache, die beliebige Konstrukte erzeugen kann, unvermeidlich (z. B. die Äquivalenz von Iteration und Rekursion).

In diesem Fall denke ich, dass es hier besser gestaltet werden könnte. Eine einzige Möglichkeit, Funktionen zu definieren, ist für mich am sinnvollsten. In diesem Fall klingt es so, als hätten die beiden Scala-Aussagen, die Sie tatsächlich haben, leicht unterschiedliche Auswirkungen, was wiederum wahrscheinlich kein gutes Design ist (wahrscheinlich am besten, wenn Sie etwas klares haben, das die Unterschiede angibt, wie ein Schlüsselwort).

Tatsächlich können Sie dieses Prinzip nicht nur auf benannte Funktionen anwenden, sondern auf jede Funktion. Warum gibt es Unterschiede bei der Definition von benannten und anonymen Funktionen? In Lima werden Funktionen immer so definiert : fn[<arguments>: <statements>]. Wenn Sie möchten, dass es "benannt" wird, können Sie es einer Variablen zuweisen: var x = fn[<arguments: <statements>]und wenn Sie es anonym an eine andere Funktion übergeben möchten : function[fn[<arguments: <statements>]]. Wenn Sie es hochziehen möchten, machen Sie es konstant const var x = fn[<arguments: <statements>]. Die einzelne Form macht deutlich, dass sie dasselbe bedeuten.

BT
quelle
Das ist ziemlich interessant, was zum constHeben führt, aber es macht vollkommen Sinn. In JS function myFuncverursacht das Heben, aber var myFunc =nicht, was vielleicht etwas weniger intuitiv ist, weil sie sich ansonsten ziemlich gleich verhalten.
Mpen
1
@mpen Ja, eigentlich macht Javascript im Wesentlichen das Gleiche. Die function fnName()...Form erzeugt tatsächlich eine Konstante, was das Heben zu einer gültigen Sache macht. Javascript macht die Dinge ziemlich verwirrend, wenn Sie das Formular verwenden, var fn = function anotherFnName()...da der Name dadurch anotherFnName nicht hochgezogen wird, obwohl er eindeutig konstant ist.
BT
2

Was Sie gepostet haben, ist eine gültige Scala und funktioniert einwandfrei.

Angesichts der Tatsache, dass die Verdoppelung (meines Wissens) keine Probleme mit Scala verursacht hat, werde ich sagen, dass dies auch für Ihre Sprache kein Problem darstellt.

Daenyth
quelle
1
Es ist in Scala gültig, es funktioniert meistens gleich, aber es bedeutet nicht dasselbe - und wenn Sie komplexere Beispiele anführen würden (Typpolymorphismus ist beispielsweise für anonyme Funktionen nicht verfügbar), würden die Unterschiede offensichtlicher.
JCora
2

Ich habe defin Scala einen grundlegenden Unterschied zwischen Lambdas und Methoden festgestellt - ich bin mir immer noch nicht sicher, ob ich implementieren möchte. Ich muss weiter darüber recherchieren und dann werde ich über meine Entscheidung berichten.

Im Wesentlichen können nur Methoden return- und wenn das Schlüsselwort von einem Lambda verwendet wird, kehrt es tatsächlich von der umfassenden Methode zurück.

Wie gesagt, ich bin mir nicht sicher, ob ich das will. Aber es könnte genug Rechtfertigung für diese Syntax sein. Oder vielleicht zu gefährlich, weil subtile Unterschiede unerwartet Schaden anrichten können.

Einzelheiten

jcora
quelle