Ri: Argomenti delle parole chiave per le funzioni@vince_faller
Fantastico esempio. Grazie per la condivisione. Correzione di errori di battitura
show(f(2, {y=14})); // 36 not 33
Ri: Argomenti delle parole chiave per le funzioni@gzmorgan0
Penso di averlo rubato da Hamcrest, ma lo usiamo da un po' ed è un metodo molto migliore in realtà. Puoi ancora fare alcune cose brutte ma controlla un po 'meglio.
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
Ri: Argomenti delle parole chiave per le funzioni@gzmorgan0 Il mio più grande problema con l'elenco kwargs è che consente di eseguire qualsiasi cosa. Ad esempio, se voglio vedere tutti i locali in una determinata funzione.
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)});
Che è un problema di sicurezza per me con il codice crittografato.
In realtà tengo le cose in un array associativo e poi eseguo un << intersezione con un array associativo predefinito per verificare che gli argomenti passati siano validi.
Quindi analizzo semplicemente le coppie di valori chiave nella funzione in modo da non dover utilizzare l'array per chiamarle.
Ho funzioni di aiuto per fare tutto questo, ma questo fa emergere una serie di problemi.Ed è più ingombrante di quanto mi piaccia.
@XanGregg , colpa mia.Ho un campo visivo molto più ristretto sulla maggior parte di queste cose.
Ri: Argomenti delle parole chiave per le funzioni@vince_faller , mi piace ancora la tua soluzione kwargs={} proposta con una modifica.IMHO Default Local è utile per script semplici, ma è rischioso per script complessi.Consiglio di gestire un elenco di variabili locali. Ad ogni modo, di seguito è riportato uno script che è una modifica della tua soluzione kwargs, ma utilizza la sintassi, {z,4} vs. z=4 come elementi nel tuo elenco kwargs e richiede un blocco di codice che può essere generico. Una funzione potrebbe utilizzare un array associativo locale per assegnare valori di "parola chiave" che implicherebbero il blocco di codice indicato di seguito, tuttavia, la sintassi della singola variabile è più ingombrante, invece di a+b sarebbe qualcosa come aa1[a] + aa1[b], quindi l'esempio utilizza le liste.
se avessi una funzione con molte variabili, ma per ogni chiamata di funzione volessi cambiarne solo alcune, potrei usare questo approccio. La chiave qui è quella
- nessuna variabile viene modificata a meno che non sia nella varList e
- i valori modificati sono locali.
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});
Ri: Argomenti delle parole chiave per le funzioniDestra. Che ci crediate o no, cerchiamo di non rompere i vecchi comportamenti JSL, anche quelli improbabili.:)
Ri: Argomenti delle parole chiave per le funzioniAh.Quindi, se qualcuno usasse quella sintassi (per qualsiasi motivo), si interromperebbe se in seguito avesse bisogno di az global.Fatto.
Ri: Argomenti delle parole chiave per le funzioniAttualmente vengono valutati gli argomenti delle funzioni utente e z=4 è un'espressione valida, quindi
f(1, z=4);
valuterebbe z=4, creando una z globale e avendo come risultato 4, quindi passerebbe il risultato all'argomento y di f.
Ri: Argomenti delle parole chiave per le funzioniPerché sarebbe necessaria una nuova sintassi?Stai dicendo per chiamare o per definire?Penso che potremmo definirli allo stesso modo.
Se una funzione non utilizza già argomenti di parole chiave, per impostazione predefinita verranno utilizzati argomenti posizionali come fa attualmente.
Ovviamente non saremmo in grado di utilizzare gli argomenti delle parole chiave prima che siano implementati, quindi non lo vedo come una violazione degli script.
La funzione
f = function({x, y=2, z=3},
show(x, y, z);
);
non romperebbe nessun altro script.
e se tutti gli script precedenti utilizzano comunque argomenti posizionali, non penso che si romperebbe nulla.
Ma se ci fossero argomenti di parole chiave che per impostazione predefinita sono posizionali se non sono state specificate parole chiave, facendo
f(1, 2, 4);
non romperebbe nulla (immagino). Ma lo permetterebbe
f(1, z=4);
Non vedo perché avrebbe bisogno di uno spazio dei nomi falso (ma ancora una volta non capisco come funzionino le funzioni sotto il cofano).
Ri: Argomenti delle parole chiave per le funzioniCiò richiederebbe una nuova sintassi che non cambierebbe gli script esistenti. Forse qualcosa come il tuo esempio con un elenco passato a un ricevitore speciale. O forse una nuova sintassi sul chiamante come uno spazio dei nomi falso: f(1, arg:z = 2).
Ri: Argomenti delle parole chiave per le funzioniGrazie.Ha sicuramente qualche problema. Il più grande probabilmente è in grado di iniettare qualsiasi variabile in una funzione e spesso causa una collisione variabile non sto attento.
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});
Ri: Argomenti delle parole chiave per le funzioniLa tua attuale soluzione per l'elenco "kwargs" è un bel trucco provvisorio.
Ri: Argomenti delle parole chiave per le funzioniCome sono definite le funzioni Jmp standard,
- tale che vicino accetta un'argomentazione supplementare noSalva .
- tale che add column accetti l'espressione Formula(...) in qualsiasi posizione all'interno di (...)
dt << New Column( "X", Formula( row() ) );
Invece di
f(2, {y=14})Potevo
f(2, y(14))
essere il modo in cui dovrebbe apparire?
Ri: Argomenti delle parole chiave per le funzioniLe funzioni interne sono costruite in C++, non in JSL. Le funzioni utente (in JSL) sono interpretate da altro codice C++ che sceglie come trasformare gli argomenti in parametri (dove gli argomenti di una funzione sono i valori esterni passati e i parametri della funzione sono i nomi delle variabili interne che fanno riferimento ai valori).
Una funzione come sin(A), scritta in C++, ha un aspetto simile
ExpressionPointer sin( ExpressionPointer E) {
double value = evaluateExpression( E );
double answer = sin( value );
return makeExpression( answer );
}
La funzione expr() in JSL, in cui la funzione restituisce semplicemente il suo argomento senza studiarlo, ha un aspetto simile
ExpressionPointer expr( ExpressionPtr E ) {
return E;
}
Sembra inutile a prima vista, ma consente all'operatore di assegnazione di valutare il lato destro di
ex = expr( a + b );
e memorizzare un albero delle espressioni in ex anziché il risultato di a+b. Un esempio più interessante è l'operatore head(a+b).
ExpressionPointer head( ExpressionPointer E ) {
return MakeExpression( E->child );
}
Questa è una rozza approssimazione dell'idea: un albero delle espressioni per a+b ha una radice, +, che ha due figli, a e b.E->child ottiene la radice, +, e la restituisce come un'espressione senza figli.
Gli sviluppatori di JMP hanno deciso di nascondere tale complessità nelle funzioni scritte dall'utente JSL per semplificare la scrittura del 99% dei casi d'uso. La maggior parte dei linguaggi che conosco non hanno espressioni che possono essere manipolate (Snobol lo fa, in un certo senso, e questo spiega la funzione patmatch() di JMP...) L'uso di una lista è un approccio ragionevole per inviare un'espressione a una funzione; l'elenco viene valutato... sullo stesso elenco. La funzione sta lavorando su una copia dell'elenco.
Argomenti di parole chiave per funzioniMi piacerebbe se nelle funzioni definite dall'utente potessimo utilizzare argomenti di parole chiave nelle chiamate, così posso farlo
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});
Qualcuno ne ha parlato Qui , ma è successo 8 anni fa, quindi ho pensato di tirarlo fuori di nuovo.
Automazione e scriptingRi: Argomenti parola chiave per funzioni - Stato modificato in: RiconosciutoRi: Argomenti di parole chiave per funzioniIl trucco con la lista è molto utile.
In realtà, la valutazione dell'elenco non è realmente necessaria per accedere alle variabili.
È possibile eseguire la scansione dell'elenco e cercare il nome giusto. tramite un ciclo for each o tramite 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});