Nachdem ich mir einige Sprachen für die funktionale Programmierung angesehen habe, habe ich mich immer gefragt, warum einige fp-Sprachen ein oder mehrere Leerzeichen für die Funktionsanwendung (und -definition) verwenden, während die meisten (alle?) Imperativen / objektorientierten Sprachen Klammern verwenden, wie es scheint sei der mathematischere Weg. Ich denke auch, dass der letztere Stil viel klarer und lesbarer ist als ohne die Parens.
Wenn wir also eine Funktion f (x) = x² haben, gibt es zwei Alternativen, um sie aufzurufen:
FP:
f x
Beispiele:
- ML, Ocaml, F #
- Haskell
- LISP, Schema (irgendwie)
Nicht-FP:
f(x)
Beispiele:
- Fast alle imperativen Sprachen (ich kenne die Kommentare / Antworten)
- Erlang
- Scala (erlaubt auch "Operator Notation" für einzelne Argumente)
Was sind die Gründe, die Klammern "wegzulassen"?
x²
als Beispiel wäre?Antworten:
funktionale sprachen sind von lambda-kalkül inspiriert . In diesem Feld werden für die Funktionsanwendung keine Klammern verwendet.
Die Lesbarkeit liegt im Auge des Betrachters. Sie sind es nicht gewohnt, es zu lesen. Es ist ein bisschen wie mit mathematischen Operatoren. Wenn Sie die Assoziativität verstehen, benötigen Sie nur wenige Parens, um die Struktur Ihres Ausdrucks zu verdeutlichen. Oft braucht man sie nicht.
Currying ist auch ein guter Grund, diese Konvention zu verwenden. In haskell können Sie Folgendes definieren:
Mit parens können Sie zwei Konventionen verwenden:
f(5, 6)
(nicht Curry) oderf(5)(6)
(Curry). Die haskell-Syntax hilft dabei, sich an das Currying-Konzept zu gewöhnen. Sie können immer noch eine nicht-Curry-Version verwenden, es ist jedoch schmerzhafter, sie mit Kombinatoren zu verwendenBeachten Sie, wie Sie in der zweiten Version dazu gezwungen werden, x als Variable zu registrieren, und dass der Unterausdruck eine Funktion ist, die eine Ganzzahl annimmt und 5 hinzufügt? Die Curry-Version ist viel leichter, wird aber auch von vielen als lesbarer angesehen.
Haskell-Programme verwenden in großem Umfang Teilanwendungen und Kombinatoren, um Abstraktionen zu definieren und zu komponieren. Dies ist also kein Spielzeugbeispiel. Eine gute Funktionsschnittstelle ist eine, bei der die Reihenfolge der Parameter eine benutzerfreundliche Verwendung ermöglicht.
Ein weiterer Punkt: Eine Funktion ohne Parameter sollte mit aufgerufen werden
f()
. In haskell schreiben Sie einfach, da Sie nur unveränderliche, verzögert ausgewertete Werte manipulierenf
, und betrachten dies als einen Wert, der bei Bedarf einige Berechnungen durchführen muss. Da die Auswertung keine Nebenwirkungen hat, ist es nicht sinnvoll, für die parameterlose Funktion und den zurückgegebenen Wert eine andere Notation zu verwenden.Es gibt auch andere Konventionen für die Funktionsanwendung:
quelle
f(a, ,b)
oderadd(a, )
oderadd(, b)
standardmäßig flexibler zu sein.Die Grundidee ist, die wichtigste Operation (Funktionsanwendung) am einfachsten zu lesen und am einfachsten zu schreiben. Ein Leerzeichen ist sehr unauffällig zu lesen und sehr einfach zu tippen.
Beachten Sie, dass dies nicht spezifisch für funktionale Sprachen ist, z. B. in Smalltalk , einer der ersten OO-Sprachen und davon inspirierten Sprachen ( Self , Newspeak , Objective-C), sondern auch in Io und von ihm inspirierten Sprachen (Ioke, Seph). Leerzeichen werden für Methodenaufrufe verwendet.
Smalltalk-Stil:
(Im letzteren Fall lautet der Name der Methode
replace:with:
.)Io-Style:
Scala erlaubt auch Leerzeichen für Methodenaufrufe:
Und lassen Sie die Klammern weg, wenn es nur ein Argument gibt:
Mit Ruby können Sie auch die Klammern weglassen:
Nicht wirklich:
Die mathematische Notation hat sich über eine lange Zeit auf schrecklich inkonsistente Weise entwickelt.
Wenn überhaupt, lassen sich funktionale Sprachen von der λ-Rechnung inspirieren, bei der die Funktionsanwendung mit Leerzeichen geschrieben wird.
quelle
Klammern für die Funktionsanwendung sind nur einer von vielen Sätteln, die Euler uns hinterlassen hat. Wie alles andere braucht auch die Mathematik Konventionen, wenn es verschiedene Möglichkeiten gibt, etwas zu tun. Wenn Ihre mathematische Ausbildung nur bis zu einem nicht-mathematischen Fach an der Universität reicht, sind Sie wahrscheinlich nicht mit den vielen Bereichen vertraut, in denen die Funktionsanwendung ohne diese unsinnigen Klammern (z. B. Differentialgeometrie, Abstrakte Algebra) problemlos abläuft. Und Sie erwähnen nicht einmal Funktionen, die infix angewendet werden (fast alle Sprachen), "outfix" wie das Aufnehmen einer Norm oder diagrammartig (Befunge, Algebraic Topology).
Als Antwort würde ich sagen, dass ein viel höherer Anteil von funktionalen Programmierern und Sprachdesignern über eine umfassende mathematische Ausbildung verfügt. Von Neumann sagt: "Junger Mann, in der Mathematik versteht man Dinge nicht. Man gewöhnt sich nur daran."
quelle
f(x)
vs.sin x
vs.x²
vs.|x|
vs.x!
vs.x + y
vs.xy
vs.½
vs. eine Summe gegen einen integralen gegen ...Obwohl Simons Antwort viel Wahres enthält, gibt es meiner Meinung nach auch einen viel praktischeren Grund. Die Art der funktionalen Programmierung erzeugt aufgrund der Funktionsverkettung und -zusammensetzung tendenziell viel mehr Klammern als die imperative Programmierung. Auch diese Verkettungs- und Kompositionsmuster lassen sich in der Regel ohne Klammern eindeutig darstellen.
Die Quintessenz ist, dass das Lesen und Verfolgen all dieser Klammern ärgerlich wird. Dies ist wahrscheinlich der Hauptgrund, warum LISP nicht beliebter ist. Wenn Sie also die Möglichkeiten der funktionalen Programmierung nutzen können, ohne übermäßige Klammern zu verwenden, werden Sprachdesigner wahrscheinlich dazu tendieren, diesen Weg zu gehen. Schließlich sind Sprachdesigner auch Sprachnutzer.
Sogar Scala ermöglicht es dem Programmierer, unter bestimmten Umständen Klammern wegzulassen, die beim Programmieren in einem funktionalen Stil häufig vorkommen, sodass Sie sozusagen das Beste aus beiden Welten herausholen. Beispielsweise:
Die Parens am Ende sind für die Assoziativität erforderlich, und die anderen sind (ebenso wie die Punkte) weggelassen. Durch diese Schreibweise wird die Verkettung der von Ihnen ausgeführten Vorgänge betont. Es mag einem imperativen Programmierer nicht vertraut sein, aber einem funktionalen Programmierer erscheint es sehr natürlich und fließend, auf diese Weise zu schreiben, ohne dass Syntax eingefügt werden muss, die dem Programm keine Bedeutung hinzufügt, sondern nur dazu da ist, den Compiler glücklich zu machen .
quelle
Beide Prämissen sind falsch.
Diese funktionalen Sprachen belegen keinen Platz für Funktionsanwendungen. Sie analysieren einfach alle Ausdrücke, die nach einer Funktion als Argument stehen.
Natürlich funktioniert es normalerweise nicht, wenn Sie weder ein Leerzeichen noch Parens verwenden, nur weil der Ausdruck nicht richtig mit einem Token versehen ist
Wenn diese Sprachen jedoch auf 1-stellige Variablennamen beschränkt wären, würde dies auch funktionieren.
Auch mathematische Konventionen erfordern normalerweise keine Klammern für die Funktionsanwendung. Mathematiker schreiben nicht nur oft sin x - für lineare Funktionen (normalerweise werden sie dann lineare Operatoren genannt) ist es auch sehr üblich, das Argument ohne Parens zu schreiben, vielleicht, weil (ähnlich wie bei jeder Funktion in der funktionalen Programmierung) lineare Funktionen oft ohne direkte Versorgung behandelt werden ein Argument.
Ihre Frage lautet also wirklich: Warum sind für manche Sprachen Klammern für die Funktionsanwendung erforderlich? Nun, anscheinend halten einige Leute, wie Sie, dies für lesbarer. Ich stimme dem überhaupt nicht zu: Ein Paar Parens ist nett, aber sobald Sie mehr als zwei von ihnen ineinander verschachtelt haben, wird es verwirrend. Lisp-Code demonstriert dies am besten, und so gut wie alle funktionalen Sprachen würden ähnlich überladen aussehen, wenn Sie überall Parens benötigen würden. Dies geschieht nicht so häufig in imperativen Sprachen, aber hauptsächlich, weil diese Sprachen nicht ausdrucksstark genug sind, um prägnante, klare Einzeiler zu schreiben.
quelle
object method: args
und Objective C[object method: args]
sowie in Ruby und Perl können Klammern in Funktions- und Methodenaufrufen weggelassen werden, sodass nur Mehrdeutigkeiten behoben werden müssen.Eine kleine historische Klarstellung: Die ursprüngliche Notation in der Mathematik war ohne Klammern !
Die Notation fx für eine beliebige Funktion von x wurde von Johan Bernoulli um 1700 eingeführt, kurz nachdem Leibniz angefangen hatte, über Funktionen zu sprechen (tatsächlich schrieb Bernoulli ϕ x ). Zuvor verwendeten viele Leute jedoch bereits Notationen wie sin x oder lx (den Logarithmus von x ) für bestimmte Funktionen von x ohne Klammern. Ich vermute, das ist der Grund, warum viele Menschen heute noch sin x anstelle von sin (x) schreiben .
Euler, der ein Schüler von Bernoulli war, adoptierte Bernoullis ϕ x und wandelte das Griechische in einen lateinischen Buchstaben um, indem er fx schrieb . Später bemerkte er, dass es leicht sein könnte, f für eine "Menge" zu verwechseln und zu glauben, dass fx ein Produkt sei, und begann, f: x zu schreiben . Daher ist die Notation f (x) nicht auf Euler zurückzuführen. Natürlich benötigt Euler Klammer aus dem gleichen Grund noch wir Klammer in funktionalen Programmiersprachen müssen: zum Beispiel zu unterscheiden (fx) + y von f (x + y) . Ich vermute, dass die Leute nach Euler die Klammer als Standard übernommen haben, weil sie hauptsächlich gesehen haben, wie Euler zusammengesetzte Ausdrücke wie f (ax + b) geschrieben hat.. Er schrieb selten nur FX .
Mehr dazu unter: Hat Euler jemals f (x) in Klammern geschrieben? .
Ich weiß nicht, ob Designer funktionaler Programmiersprachen oder die Erfinder der Lambda-Rechnung die historischen Wurzeln ihrer Notation kannten. Persönlich finde ich die Notation ohne Klammern natürlicher.
quelle