Betreff: Schlüsselwortargumente für Funktionen@vince_faller
Cooles Beispiel. Danke für das Teilen. Tippfehlerkorrektur
show(f(2, {y=14})); // 36 not 33
Betreff: Schlüsselwortargumente für Funktionen@gzmorgan0
Ich glaube, ich habe das von Hamcrest gestohlen, aber wir benutzen es schon eine Weile und es ist tatsächlich eine viel bessere Methode. Sie können immer noch einige schlechte Dinge tun, aber es überprüft ein wenig besser.
Names default to here(1);
f = function({x, kwargs = {}},
{DEFAULT LOCAL},
// kwargs
y = try(kwargs["y"], 2); // so the default is 2
z = try(kwargs["z"], 3); // 3
a = try(kwargs["a"], Expr(y+z)); // Expr(y+z)
r = x + y + z + eval(a);
return(r);
);
show(f(2)); // 12
show(f(2, {y=14})); // 33
show(f(2, {wrong=14})); // still 12
show(f(2, {y=3, a=Expr(y^2)})); // 17
Betreff: Schlüsselwortargumente für Funktionen@gzmorgan0 Mein größtes Problem mit der kwargs-Liste ist, dass damit alles ausgeführt werden kann. Zum Beispiel, wenn ich alle Einheimischen in einer bestimmten Funktion sehen möchte.
f = function({x, kwargs = {}},
{y = 2, z = 3, a = Expr(y + z)},
evallist(kwargs);
r = x + y + z;
return(r);
);
f(14, {print(namespace("local") << Get Contents)});
Was für mich ein Sicherheitsproblem mit verschlüsseltem Code ist.
Ich behalte die Dinge tatsächlich in einem assoziativen Array und mache dann eine <<-Schnittmenge mit einem standardmäßigen assoziativen Array, um zu überprüfen, ob die übergebenen Argumente gültig sind.
Dann parse ich einfach die Schlüssel-Wert-Paare in die Funktion, damit ich nicht das Array verwenden muss, um sie aufzurufen.
Ich habe Hilfsfunktionen, um all dies zu tun, aber das bringt seine eigenen Probleme mit sich.Und es ist umständlicher als mir lieb ist.
@XanGregg , mein Fehler.Bei den meisten dieser Dinge habe ich ein viel engeres Sichtfeld.
Betreff: Schlüsselwortargumente für Funktionen@vince_faller , Ich mag immer noch Ihre vorgeschlagene kwargs={}-Lösung mit einer Modifikation.IMHO Default Local ist gut für einfaches Skripting, aber riskant für komplexe Skripte.Ich empfehle, eine Liste lokaler Variablen zu verwalten. Wie auch immer, unten ist ein Skript, das eine Modifikation Ihrer kwargs-Lösung ist, aber die Syntax {z,4} vs. z=4 als Elemente in Ihrer kwargs-Liste verwendet und einen Codeblock erfordert, der generisch sein kann. Eine Funktion könnte ein lokales assoziatives Array verwenden, um "Schlüsselwort"-Werte zuzuweisen, was den unten angegebenen Codeblock implizieren würde, aber dann ist die individuelle Variablensyntax umständlicher, statt a+b wäre es so etwas wie aa1[a] + aa1[b], also verwendet das Beispiel Listen.
Wenn ich eine Funktion mit vielen Variablen hätte, aber für jeden Funktionsaufruf nur wenige ändern wollte, könnte ich diesen Ansatz verwenden. Der Schlüssel hier ist das
- keine Variable wird geändert, es sei denn, sie befindet sich in der varList, und
- geänderte Werte sind lokal.
Names Default To Here( 1 );
//simple example
g1 = Function({kwargs={}}, {Default Local},
varList = {a,b,c,d,e,f};
valList = {1,2,3,4,5,6};
For(i=1, i<=nitems(kwargs), i++,
//each item must be a list of 2 values.
If(IsList(kwargs[i]),
Try(valList[loc(varList,kwargs[i][1])] = kwargs[i][2])
);
);
Eval( EvalExpr( Expr(varList) = Expr(valList)) ) ;
show(a,b,c,d,e,f);
);
myList = {{a,10},{y,-44},{f,20}};
g1(myList);
// [+] no variable gets changed unless it is in the variable list
// [-] varList and valList need to be defined
// [-] lines 7-13 would need to be added to each function, could be a global expression
// [-] instead of z=4 syntax, {z,4} syntax is required
//------Modification of Vince Faller script
f = function({x, kwargs={}},
{DEFAULT LOCAL},
// optional
varList = {x, y};
valList = {2,3};
For(i=1, i<=nitems(kwargs), i++,
//each item must be a list of 2 values.
If(IsList(kwargs[i]),
Try(valList[loc(varList,kwargs[i][1])] = kwargs[i][2])
);
);
Eval( EvalExpr( Expr(varList) = Expr(valList)) ) ;
print("Before Bad Call");
show(y);
print("Bad Call");
//even though f2 is default local,
//because it's not explicit in the function it writes to here
f2(1, { {b,3}, {y,5}});
print("After Bad Call");
show(y);
);
f2 = function({a, kwargs={}},
{DEFAULT LOCAL},
varList= {b,c};
valList = {2,3};
For(i=1, i<=nitems(kwargs), i++,
//each item must be a list of 2 values.
If(IsList(kwargs[i]),
Try(valList[loc(varList,kwargs[i][1])] = kwargs[i][2])
);
);
Eval( EvalExpr( Expr(varList) = Expr(valList)) ) ;
show(a, b, c);
);
f(1, {z=2});
Betreff: Schlüsselwortargumente für FunktionenRechts. Ob Sie es glauben oder nicht, wir versuchen, alte JSL-Verhaltensweisen nicht zu brechen, selbst unwahrscheinliche.:)
Betreff: Schlüsselwortargumente für FunktionenAhh.Wenn also jemand diese Syntax verwendet (aus welchen Gründen auch immer), würde sie kaputt gehen, wenn er später az global benötigte.Habe es.
Betreff: Schlüsselwortargumente für FunktionenDerzeit werden Argumente für Benutzerfunktionen ausgewertet und z = 4 ist ein gültiger Ausdruck, also
f(1, z=4);
würde z = 4 auswerten, ein globales z erstellen und ein Ergebnis von 4 haben und das Ergebnis dann an das y-Argument von f übergeben.
Betreff: Schlüsselwortargumente für FunktionenWarum wäre eine neue Syntax erforderlich?Sagen Sie zum Aufrufen oder zum Definieren?Ich denke, wir könnten sie auf die gleiche Weise definieren.
Wenn eine Funktion bereits keine Schlüsselwortargumente verwendet, verwendet sie standardmäßig Positionsargumente, wie sie es derzeit tut.
Offensichtlich wären wir nicht in der Lage, Schlüsselwortargumente zu verwenden, bevor sie implementiert sind, also sehe ich das nicht als kaputte Skripte an.
Die Funktion
f = function({x, y=2, z=3},
show(x, y, z);
);
würde keine anderen Skripte brechen.
und wenn alle vorherigen Skripte sowieso Positionsargumente verwenden, dann glaube ich nicht, dass es irgendetwas kaputt machen würde.
Aber wenn ich Schlüsselwortargumente hätte, die standardmäßig auf Positionsangaben gesetzt sind, wenn keine Schlüsselwörter angegeben wurden, tue ich es
f(1, 2, 4);
würde nichts kaputt machen (glaube ich). Aber es würde einfach zulassen
f(1, z=4);
Ich verstehe nicht, warum es einen gefälschten Namensraum benötigen würde (aber andererseits verstehe ich nicht, wie Funktionen unter der Haube funktionieren).
Betreff: Schlüsselwortargumente für FunktionenDies würde eine neue Syntax erfordern, die bestehende Skripte nicht ändert. Vielleicht so etwas wie Ihr Beispiel mit einer Liste, die an einen speziellen Empfänger übergeben wird. Oder vielleicht eine neue Syntax auf dem Aufrufer wie ein gefälschter Namespace: f(1, arg:z = 2).
Betreff: Schlüsselwortargumente für FunktionenVielen Dank.Es hat definitiv ein paar Probleme. Das Größte ist wahrscheinlich, dass es möglich ist, beliebige Variablen in eine Funktion einzufügen, und verursacht häufig Variablenkollisionen. Ich bin nicht vorsichtig.
Names default to here(1);
f = function({x, kwargs={}},
{DEFAULT LOCAL},
// optional
y = 2;
z = 3;
evallist(kwargs);
print("Before Bad Call");
show(y);
print("Bad Call");
//even though f2 is default local,
//because it's not explicit in the function it writes to here
f2(1, {b=3, y=5});
print("After Bad Call");
show(y);
);
f2 = function({a, kwargs={}},
{DEFAULT LOCAL},
b=2;
c=3;
evallist(kwargs);
show(a, b, c);
);
f(1, {z=2});
Betreff: Schlüsselwortargumente für FunktionenIhre aktuelle "kwargs"-Listenlösung ist ein netter Zwischentrick.
Betreff: Schlüsselwortargumente für FunktionenWie sind die Standard-Jmp-Funktionen definiert?
- so dass schließen akzeptiert ein ergänzendes Argument neinSpeichern .
- So dass die Spalte hinzufügen den Ausdruck Formula(...) an jeder Position innerhalb von (...) akzeptiert.
dt << New Column( "X", Formula( row() ) );
Anstatt
f(2, {y=14})könnte
f(2, y(14))
so sein, wie es aussehen sollte?
Betreff: Schlüsselwortargumente für FunktionenDie internen Funktionen sind in C++ und nicht in JSL erstellt. Die Benutzerfunktionen (in JSL) werden von anderem C++-Code interpretiert, der auswählt, wie Argumente in Parameter umgewandelt werden (wobei die Argumente einer Funktion die übergebenen externen Werte sind und die Parameter der Funktion die internen Variablennamen sind, die auf die Werte verweisen).
Eine in C++ geschriebene Funktion wie sin(A) sieht ungefähr so aus
ExpressionPointer sin( ExpressionPointer E) {
double value = evaluateExpression( E );
double answer = sin( value );
return makeExpression( answer );
}
Die expr()-Funktion in JSL, bei der die Funktion einfach ihr Argument zurückgibt, ohne es zu studieren, sieht in etwa so aus
ExpressionPointer expr( ExpressionPtr E ) {
return E;
}
Das erscheint auf den ersten Blick nutzlos, aber es ermöglicht dem Zuweisungsoperator, die rechte Seite von auszuwerten
ex = expr( a + b );
und einen Ausdrucksbaum in ex speichern, anstatt das Ergebnis von a+b. Ein interessanteres Beispiel ist der Head(a+b)-Operator.
ExpressionPointer head( ExpressionPointer E ) {
return MakeExpression( E->child );
}
Das ist eine grobe Annäherung an die Idee: Ein Ausdrucksbaum für a+b hat eine Wurzel +, die zwei untergeordnete Elemente hat, a und b.E->child ruft die Wurzel + ab und gibt diese als Ausdruck ohne untergeordnete Elemente zurück.
Die JMP-Entwickler haben beschlossen, diese Komplexität in den vom JSL-Benutzer geschriebenen Funktionen zu verbergen, um das Schreiben der 99 % der Anwendungsfälle zu vereinfachen. Die meisten Sprachen, mit denen ich vertraut bin, haben keine Ausdrücke, die manipuliert werden können (Snobol tut dies gewissermaßen, und das erklärt die patmatch()-Funktion von JMP ...) Die Verwendung einer Liste ist ein sinnvoller Ansatz zum Senden eines Ausdrucks an eine Funktion. Die Liste wird ausgewertet ... zur gleichen Liste. Die Funktion arbeitet an einer Kopie der Liste.
Schlüsselwortargumente für FunktionenIch würde es lieben, wenn wir in benutzerdefinierten Funktionen Schlüsselwortargumente in den Aufrufen verwenden könnten, damit ich das tun kann
Names default to here(1);
f = function({x, y=2, z=3},
show(x, y, z);
);
print("What I'd like to do");
f(1, z=2);
//I want it to be 1, 2, 2
//instead of having to do
f = function({x, kwargs={}},
{DEFAULT LOCAL},
// optional
y = 2;
z = 3;
evallist(kwargs);
show(x, y, z);
);
print("Using List");
f(1, {z=2});
Jemand hat es erwähnt Hier , aber es war vor 8 Jahren, also dachte ich, ich würde es noch einmal erwähnen.
Automatisierung und SkripterstellungRe: Keyword arguments for functions - Status changed to: AcknowledgedBetreff: Schlüsselwortargumente für FunktionenDer Trick mit der Liste ist sehr nützlich.
Eigentlich ist die Auswertung der Liste für den Zugriff auf die Variablen nicht unbedingt erforderlich.
Man kann die Liste scannen und nach dem richtigen Namen suchen, entweder mit einer For-Each-Schleife oder über Extract Expr.
Names default to here(1);
get = Function ({var}, Eval(Eval Expr(Arg(Extract Expr(kwarg, Expr(Name Expr(var)) = wild()),2))));
f = function({x, kwargs={}},
{DEFAULT LOCAL},
print(get(Expr(z)));
);
f(1, {z=2});