Warum ist das Binden in den meisten Sprachen kein natives Merkmal?

11

IMHO ist das Binden einer Variablen an eine andere Variable oder einen Ausdruck ein sehr verbreitetes Szenario in der Mathematik. Tatsächlich denken viele Schüler am Anfang, dass der Zuweisungsoperator (=) eine Art Bindung ist. In den meisten Sprachen wird die Bindung jedoch nicht als native Funktion unterstützt. In einigen Sprachen wie C # wird die Bindung in einigen Fällen unter bestimmten Bedingungen unterstützt.

IMHO war die Implementierung dieser Funktion als native Funktion jedoch so einfach wie das Ändern des folgenden Codes:

int a,b,sum;
sum := a + b;
a = 10;
b = 20;
a++;

zu diesem-

int a,b,sum;
a = 10;
sum = a + b;
b = 20;
sum = a + b;
a++;
sum = a + b;

Dies bedeutet, dass die Bindungsanweisung nach jeder Anweisung als Zuweisung platziert wird, wobei die Werte einer der im Ausdruck enthaltenen Variablen auf der rechten Seite geändert werden. Danach können redundante Anweisungen (oder die Optimierung in der Assembly nach der Kompilierung) gekürzt werden.

Warum wird es in den meisten Sprachen nicht nativ unterstützt? Speziell in der C-Sprachfamilie?

Aktualisieren:

Aus unterschiedlichen Meinungen denke ich, ich sollte diese vorgeschlagene "Bindung" genauer definieren.

  • Dies ist eine Einbahnstraße. Nur die Summe ist an a + b gebunden, nicht umgekehrt.
  • Der Umfang der Bindung ist lokal.
  • Sobald die Bindung hergestellt ist, kann sie nicht mehr geändert werden. Das heißt, sobald die Summe an a + b gebunden ist, ist die Summe immer a + b.

Hoffe, die Idee ist jetzt klarer.

Update 2:

Ich wollte nur diese P # -Funktion . Hoffe, dass es in Zukunft dort sein wird.

Gulshan
quelle
14
Möglicherweise, weil jeder Compiler-Entwickler, der versucht hat, diese Funktion zu C hinzuzufügen, aufgespürt und erschossen wurde.
Pete Wilson
Ich spreche von Einwegbindung (von rechts nach links), nicht von Zweiwegbindung. Die Bindung wirkt sich immer nur auf eine Variable aus.
Gulshan
2
Für das, was es wert ist, ist diese Art von programmatischer Sichtweise auf dem Vormarsch: reaktive Programmierung. Was Sie beschreiben, wird auch durch Tabellenkalkulationsprogramme wie Excel verkörpert, bei denen es sich im Wesentlichen um Datenbindung (oder reaktive Programmierung) für Steroide handelt.
Mike Rosenblum
11
Es ist vielleicht nicht ein Merkmal der „ die meisten“ Programmiersprachen sein, aber es ist ein Merkmal der beliebtestenen Programmiersprache: Excel.
Jörg W Mittag
2
Dank Ausdrucksbäumen ist dies bereits in C # möglich. Ich habe gestern darüber gebloggt
HappyNomad

Antworten:

9

Sie verwechseln Programmieren mit Mathematik. Nicht einmal funktionale Programmierung ist rein mathematisch, obwohl sie viele Ideen entlehnt und sie in etwas verwandelt, das ausgeführt und für die Programmierung verwendet werden kann. Imperative Programmierung (die die meisten C-inspirierten Sprachen umfasst, mit Ausnahme von JavaScript und den neueren Ergänzungen zu C #) hat fast nichts mit Mathematik zu tun. Warum sollten sich diese Variablen also wie Variablen in Mathematik verhalten?

Sie müssen berücksichtigen, dass dies nicht immer das ist, was Sie wollen. So viele Menschen werden von Verschlüssen gebissen, die speziell in Schleifen erstellt wurden, weil Verschlüsse die Variable behalten und nicht irgendwann eine Kopie ihres Werts, dh for (i = 0; i < 10; i++) { var f = function() { return i; }; /* store f */ }zehn Verschlüsse erstellen, die zurückkehren 9. Sie müssten also beide Möglichkeiten unterstützen - was die doppelten Kosten für das "Komplexitätsbudget" und einen weiteren Betreiber bedeutet. Möglicherweise auch Inkompatibilitäten zwischen Code, der dies verwendet, und Code, der dies nicht verwendet, es sei denn, das Typsystem ist ausgefeilt genug (mehr Komplexität!).

Auch eine effiziente Implementierung ist sehr schwierig. Die naive Implementierung fügt jeder Aufgabe einen konstanten Overhead hinzu , der sich in imperativen Programmen schnell summieren kann. Andere Implementierungen können Aktualisierungen verzögern, bis die Variable gelesen wird. Dies ist jedoch erheblich komplexer und hat auch dann noch Overhead, wenn die Variable nie wieder gelesen wird. Ein ausreichend intelligenter Compiler kann beide optimieren, aber ausreichend intelligente Compiler sind selten und erfordern viel Aufwand beim Erstellen (beachten Sie, dass dies nicht immer so einfach ist wie in Ihrem Beispiel, insbesondere wenn die Variablen einen breiten Anwendungsbereich haben und Multithreading ins Spiel kommt!).

Beachten Sie, dass es bei der reaktiven Programmierung im Wesentlichen darum geht (soweit ich das beurteilen kann), also existiert sie. In traditionellen Programmiersprachen ist das einfach nicht so üblich. Und ich wette, einige der Implementierungsprobleme, die ich im vorherigen Absatz aufgeführt habe, sind gelöst.


quelle
Ich denke, Sie haben 3 Punkte - 1) Es ist keine zwingende Stilprogrammierung. Heutzutage sind die meisten Sprachen nicht auf einige Paradigmen beschränkt. Ich denke nicht, dass dies aus diesem Paradigmenstil heraus eine gute Logik ist. 2) Komplexität. Sie haben gezeigt, dass viele komplexere Dinge bereits unterstützt werden. Warum nicht dieser? Ich weiß, dass Betreiber, die fast keine Verwendung haben, unterstützt werden. Und das ist eine völlig neue Funktion. Wie kann es also zu Kompatibilitätsproblemen kommen? Ich ändere oder lösche nichts aus. 3) Harte Implementierung. Ich denke, die heutigen Compiler haben bereits die Möglichkeit, dies zu optimieren.
Gulshan
1
@ Gulshan: (1) Kein Programmierparadigma ist Mathematik. FP ist nah dran, aber FP ist relativ selten und die unreinen FP-Sprachen mit veränderlichen Variablen behandeln diese Variablen auch nicht so, als wären sie aus der Mathematik. Das einzige Paradigma, in dem dies existiert, ist die reaktive Programmierung, aber die reaktive Programmierung ist nicht bekannt oder wird nicht häufig verwendet (in traditionellen Programmiersprachen). (2) Alles hat einige Komplexitätskosten und einen Wert. Dies hat ziemlich hohe Kosten und IMHO relativ wenig Wert, außer in einigen wenigen Domänen. Es ist also nicht das erste, was ich meiner Sprache hinzufügen würde, es sei denn, es zielt speziell auf diese Domänen ab.
Warum nicht noch ein Werkzeug in unserer Box haben? Sobald ein Werkzeug vorhanden ist, werden die Benutzer es verwenden. Eine Frage. Wenn eine Sprache wie C oder C ++ diese Funktion implementieren und nach Ihrer Meinung fragen möchte, würden Sie sagen: "Geben Sie es nicht. Weil es Ihnen zu schwer wird und die Leute damit durcheinander kommen."
Gulshan
@ Gulshan: Zu (3): Es ist nicht immer (nicht zu sagen, selten) so einfach wie in Ihrem Beispiel. Wenn Sie es in den globalen Bereich stellen, benötigen Sie plötzlich Optimierungen für die Verbindungszeit. Fügen Sie dann eine dynamische Verknüpfung hinzu, und Sie können zur Kompilierungszeit nicht einmal etwas tun. Sie benötigen einen sehr intelligenten Compiler und eine sehr clevere Laufzeit einschließlich JIT, um dies gut zu machen. Berücksichtigen Sie auch die Anzahl der Aufgaben in jedem nicht trivialen Programm. Weder Sie noch ich können diese Komponenten schreiben. Es gibt höchstens einige Leute, die sich für dieses Thema interessieren und interessieren. Und sie könnten bessere Dinge zu tun haben.
@ Gulshan: Ich würde sie bitten, dem unglaublich komplexen Biest, das C ++ bereits ist, keine Funktion hinzuzufügen, oder ich würde sie bitten, C nicht für Dinge zu verwenden, die über die Systemprogrammierung hinausgehen (was nicht einer der Bereiche ist, in denen dies sehr nützlich ist ). Abgesehen davon bin ich alles für aufregende neue Funktionen, aber nur dann, wenn noch genügend Komplexitätsbudget übrig ist (viele Sprachen haben ihre immer erschöpft) und die Funktion nützlich ist für das, was die Sprache tun soll - wie ich bereits sagte Es gibt nur wenige Bereiche, in denen dies nützlich ist.
3

Es passt sehr schlecht zu den meisten Programmiermodellen. Es würde eine Art völlig unkontrollierte Fernwirkung darstellen, bei der man den Wert von Hunderten oder Tausenden von Variablen und Objektfeldern durch eine einzige Zuweisung zerstören könnte.

jprete
quelle
Dann würde ich vorschlagen, eine Regel aufzustellen, dass die gebundene Variable, dh die linke Seite, auf keine andere Weise geändert wird. Und ich spreche von einer Einbahnstraße, nicht von einer Einbahnstraße. Wenn Sie meiner Frage folgen, können Sie sehen. Es ist also keine andere Variable betroffen.
Gulshan
Das ist egal. Jedes Mal, wenn Sie an aoder schreiben b, müssen Sie die Auswirkungen auf jeden einzelnen verwendeten Ort sumund jeden Ort, den Sie lesen sum, berücksichtigen. Sie müssen überlegen, was aund was Sie btun. In nicht trivialen Fällen kann dies kompliziert werden, insbesondere wenn sich der tatsächlich gebundene Ausdruck zur sumLaufzeit ändern kann.
jprete
Ich würde die Regel empfehlen, dass der Bindungsausdruck nicht geändert werden kann, sobald die Bindung abgeschlossen ist. Auch eine Zuordnung ist nicht möglich. Es wird wie eine Halbkonstante sein, die einmal an einen Ausdruck gebunden ist. Das heißt, sobald die Summe an a + b gebunden ist, wird sie während des restlichen Programms immer a + b sein.
Gulshan
3

Weißt du, ich habe das nervige Gefühl, dass reaktive Programmierung in einer Web2.0-Umgebung cool sein könnte. Warum das Gefühl? Nun, ich habe diese eine Seite, die meistens eine Tabelle ist, die sich als Reaktion auf onClick-Ereignisse in Tabellenzellen ständig ändert. Und Zellklicks bedeuten oft, die Klasse aller Zellen in einer Spalte oder Zeile zu ändern. und das bedeutet endlose Schleifen von getRefToDiv () und dergleichen, um andere verwandte Zellen zu finden.

IOW, viele der ~ 3000 Zeilen JavaScript, die ich geschrieben habe, tun nichts anderes, als Objekte zu lokalisieren. Vielleicht könnte reaktive Programmierung all das zu geringen Kosten tun; und bei einer enormen Reduzierung der Codezeilen.

Was haltet ihr davon? Ja, ich stelle fest, dass meine Tabelle viele Tabellenkalkulationsfunktionen enthält.

Pete Wilson
quelle
3

Ich denke, was Sie beschreiben, wird als Tabellenkalkulation bezeichnet:

A1=5
B1=A1+1
A1=6

... dann Bewertung der B1Renditen 7.

BEARBEITEN

Die C-Sprache wird manchmal als "tragbare Baugruppe" bezeichnet. Es ist eine zwingende Sprache, während Tabellenkalkulationen usw. deklarative Sprachen sind. Das Sagen B1=A1+1und Erwarten B1einer Neubewertung bei Änderungen A1ist definitiv deklarativ. Deklarative Sprachen (von denen funktionale Sprachen eine Teilmenge sind) werden im Allgemeinen als übergeordnete Sprachen betrachtet, da sie weiter von der Funktionsweise der Hardware entfernt sind.

In einem ähnlichen Zusammenhang sind Automatisierungssprachen wie die Kontaktplanlogik normalerweise deklarativ. Wenn Sie eine Sprosse der Logik schreiben , die sagen , output A = input B OR input Ces wird neu zu bewerten diese Aussage immer wieder und Akann , wann immer ändern Boder CÄnderungen. Andere Automatisierungssprachen wie das Funktionsblockdiagramm (mit dem Sie möglicherweise vertraut sind, wenn Sie Simulink verwendet haben) sind ebenfalls deklarativ und werden kontinuierlich ausgeführt.

Einige (eingebettete) Automatisierungsgeräte sind in C programmiert, und wenn es sich um ein Echtzeitsystem handelt, verfügt es wahrscheinlich über eine Endlosschleife, die die Logik immer wieder neu ausführt, ähnlich wie die Kontaktplanlogik ausgeführt wird. In diesem Fall könnten Sie in Ihre Hauptschleife schreiben:

A = B || C;

... und da es ständig ausgeführt wird, wird es deklarativ. Awird ständig neu bewertet.

Scott Whitlock
quelle
3

C, C ++, Ziel-C:

Blöcke bieten die Bindungsfunktion, nach der Sie suchen.

In Ihrem Beispiel:

Summe: = a + b;

Sie setzen sumauf den Ausdruck a + bin einem Kontext, in dem aund bVariablen vorhanden sind. Sie können genau das mit einem "Block" (alias Closure, alias Lambda-Ausdruck) in C, C ++ oder Objective-C mit Apples Erweiterungen (pdf) tun :

__block int a = 0, b = 0;           // declare a and b
int (^sum)(void);                   // declare sum
sum = ^(void){return a + b;};       // sum := a + b

Dies setzt sumauf einen Block, der die Summe von a und b zurückgibt. Der __blockSpeicherklassenspezifizierer gibt dies an aund bkann sich ändern. In Anbetracht dessen können wir den folgenden Code ausführen:

printf("a=%d\t b=%d\t sum=%d\n", a, b, sum());
a = 10;
printf("a=%d\t b=%d\t sum=%d\n", a, b, sum());
b = 32;
printf("a=%d\t b=%d\t sum=%d\n", a, b, sum());
a++;
printf("a=%d\t b=%d\t sum=%d\n", a, b, sum());

und erhalten Sie die Ausgabe:

a=0      b=0     sum=0
a=10     b=0     sum=10
a=10     b=32    sum=42
a=11     b=32    sum=43

Der einzige Unterschied zwischen der Verwendung eines Blocks und der von Ihnen vorgeschlagenen "Bindung" besteht in dem leeren Klammerpaar in sum(). Der Unterschied zwischen sumund sum()ist der Unterschied zwischen einem Ausdruck und dem Ergebnis dieses Ausdrucks. Beachten Sie, dass wie bei Funktionen die Klammern nicht leer sein müssen - Blöcke können ebenso wie Funktionen Parameter annehmen.

Caleb
quelle
2

C ++

Aktualisiert, um generisch zu sein. Parametriert bei Rückgabe- und Eingabetypen. Kann jede binäre Operation liefern, die die parametrisierten Typen erfüllt. Code berechnet das Ergebnis auf Anfrage. Es versucht, die Ergebnisse nicht neu zu berechnen, wenn es damit durchkommt. Nehmen Sie dies heraus, wenn dies unerwünscht ist (aufgrund von Nebenwirkungen, weil die enthaltenen Objekte groß sind, aus irgendeinem Grund).

#include <iostream>

template <class R, class A, class B>
class Binding {
public:
    typedef R (*BinOp)(A, B);
    Binding (A &x, B &y, BinOp op)
        : op(op)
        , rx(x)
        , ry(y)
        , useCache(false)
    {}
    R value () const {
        if (useCache && x == rx && y == ry) {
            return cache;
        }
        x = rx;
        y = ry;
        cache = op(x, y);
        useCache = true;
        return cache;
    }
    operator R () const {
        return value();
    }
private:
    BinOp op;
    A &rx;
    B &ry;
    mutable A x;
    mutable B y;
    mutable R cache;
    mutable bool useCache;
};

int add (int x, int y) {
    return x + y;
}

int main () {
    int x = 1;
    int y = 2;
    Binding<int, int, int> z(x, y, add);
    x += 55;
    y *= x;
    std::cout << (int)z;
    return 0;
}
Thomas Eding
quelle
Obwohl es die Frage nicht beantwortet, gefällt mir die Idee, die Sie vorgestellt haben. Kann es eine allgemeinere Version geben?
Gulshan
@ Gulshan: Aktualisiert
Thomas Eding