Re : Arguments de mots clés pour les fonctions@vince_faller
Exemple sympa. Merci d'avoir partagé. Correction de faute de frappe
show(f(2, {y=14})); // 36 not 33
Re : Arguments de mots clés pour les fonctions@gzmorgan0
Je pense que j'ai volé ça à hamcrest mais nous l'utilisons depuis un moment et c'est une bien meilleure méthode en fait. Vous pouvez toujours faire de mauvaises choses, mais cela vérifie un peu mieux.
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
Re : Arguments de mots clés pour les fonctions@gzmorgan0 Mon plus gros problème avec la liste kwargs est qu'elle permet d'exécuter n'importe quoi. Par exemple, si je veux voir tous les locaux dans une fonction donnée.
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)});
Ce qui est un problème de sécurité pour moi avec le code crypté.
En fait, je garde les choses dans un tableau associatif, puis je fais une intersection << avec un tableau associatif par défaut pour vérifier que les arguments passés sont valides.
Ensuite, j'analyse simplement les paires clé-valeur dans la fonction afin de ne pas avoir à utiliser le tableau pour les appeler.
J'ai des fonctions d'aide pour faire tout cela, mais cela fait ressortir son propre ensemble de problèmes.Et c'est plus encombrant que j'aime.
@XanGregg , ma faute.J'ai un champ de vision beaucoup plus étroit sur la plupart de ces choses.
Re : Arguments de mots clés pour les fonctions@vince_faller , j'aime toujours votre solution kwargs={} proposée avec une modification.IMHO Default Local est agréable pour les scripts simples, mais risqué pour les scripts complexes.Je recommande de gérer une liste de variables locales. Quoi qu'il en soit, ci-dessous se trouve un script qui est une modification de votre solution kwargs, mais utilise la syntaxe, {z,4} vs. z=4 comme éléments de votre liste kwargs et nécessite un bloc de code qui peut être générique. Une fonction pourrait utiliser un tableau associatif local pour attribuer des valeurs de "mot clé" qui impliqueraient le bloc de code indiqué ci-dessous, cependant, la syntaxe de la variable individuelle est plus lourde, au lieu de a+b, ce serait quelque chose comme aa1[a] + aa1[b], donc l'exemple utilise des listes.
si j'avais une fonction avec de nombreuses variables, mais que pour chaque appel de fonction je ne voulais en changer que quelques-unes, je pourrais utiliser cette approche. La clé ici est que
- aucune variable n'est modifiée à moins qu'elle ne soit dans la varList, et
- les valeurs modifiées sont locales.
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});
Re : Arguments de mots clés pour les fonctionsDroite. Croyez-le ou non, nous essayons de ne pas casser les anciens comportements JSL, même les plus improbables.:)
Re : Arguments de mots clés pour les fonctionsAhh.Donc, si quelqu'un utilisait cette syntaxe (pour une raison quelconque), elle se briserait s'il avait besoin d'un az global plus tard.J'ai compris.
Re : Arguments de mots clés pour les fonctionsActuellement, les arguments des fonctions utilisateur sont évalués et z=4 est une expression valide, donc
f(1, z=4);
évaluerait z=4, créant un z global et ayant un résultat de 4, puis passerait le résultat à l'argument y de f.
Re : Arguments de mots clés pour les fonctionsPourquoi une nouvelle syntaxe serait-elle nécessaire ?Dites-vous pour appeler ou pour définir?Je pense qu'on pourrait les définir de la même manière.
Si une fonction n'utilise déjà pas d'arguments de mots clés, elle utilisera par défaut des arguments positionnels comme elle le fait actuellement.
De toute évidence, nous ne serions pas en mesure d'utiliser des arguments de mots clés avant qu'ils ne soient implémentés, donc je ne vois pas cela comme des scripts de rupture.
La fonction
f = function({x, y=2, z=3},
show(x, y, z);
);
ne casserait aucun autre script.
et si tous les scripts précédents utilisent de toute façon des arguments positionnels, je ne pense pas que cela casserait quoi que ce soit.
Mais s'il y avait des arguments de mots-clés qui par défaut étaient positionnels si aucun mot-clé n'était spécifié, faire
f(1, 2, 4);
ne casserait rien (je suppose). Mais cela permettrait juste
f(1, z=4);
Je ne vois pas pourquoi il aurait besoin d'un faux espace de noms (mais encore une fois, je ne comprends pas comment les fonctions fonctionnent sous le capot).
Re : Arguments de mots clés pour les fonctionsCela nécessiterait une nouvelle syntaxe qui ne modifierait pas les scripts existants. Peut-être quelque chose comme votre exemple avec une liste transmise à un récepteur spécial. Ou peut-être une nouvelle syntaxe sur l'appelant comme un faux espace de noms : f(1, arg:z = 2).
Re : Arguments de mots clés pour les fonctionsMerci.Il a certainement quelques problèmes. Le plus gros étant probablement capable d'injecter n'importe quelle variable dans une fonction et provoque souvent une collision variable, je ne fais pas attention.
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});
Re : Arguments de mots clés pour les fonctionsVotre solution de liste "kwargs" actuelle est une belle astuce provisoire.
Re : Arguments de mots clés pour les fonctionsComment sont définies les fonctions standards de Jmp,
- tel que fermer accepte un argument supplémentaire pas d'enregistrement .
- tel que add column accepte l'expression Formula(...) à n'importe quelle position dans (...)
dt << New Column( "X", Formula( row() ) );
Au lieu de
f(2, {y=14})pourrait
f(2, y(14))
être la façon dont il devrait ressembler?
Re : Arguments de mots clés pour les fonctionsLes fonctions internes sont construites en C++, pas en JSL. Les fonctions utilisateur (en JSL) sont interprétées par un autre code C++ qui choisit comment transformer les arguments en paramètres (où les arguments d'une fonction sont les valeurs externes transmises et les paramètres de la fonction sont les noms de variables internes qui font référence aux valeurs.)
Une fonction comme sin(A), écrite en C++, ressemble à quelque chose comme
ExpressionPointer sin( ExpressionPointer E) {
double value = evaluateExpression( E );
double answer = sin( value );
return makeExpression( answer );
}
La fonction expr () dans JSL, où la fonction renvoie simplement son argument sans l'étudier, ressemble à quelque chose comme
ExpressionPointer expr( ExpressionPtr E ) {
return E;
}
Cela semble inutile à première vue, mais cela permet à l'opérateur d'affectation d'évaluer le côté droit de
ex = expr( a + b );
et stocker un arbre d'expression dans ex plutôt que le résultat de a+b. Un exemple plus intéressant est l'opérateur head(a+b).
ExpressionPointer head( ExpressionPointer E ) {
return MakeExpression( E->child );
}
C'est une approximation grossière de l'idée : un arbre d'expression pour a+b a une racine, +, qui a deux enfants, a et b.E->child obtient la racine, +, et la renvoie sous la forme d'une expression sans enfant.
Les développeurs JMP ont pris la décision de masquer cette complexité dans les fonctions écrites par l'utilisateur JSL afin de faciliter l'écriture des 99 % de cas d'utilisation. La plupart des langages que je connais n'ont pas d'expressions qui peuvent être manipulées (Snobol le fait, en quelque sorte, et cela explique la fonction patmatch() de JMP ...) L'utilisation d'une liste est une approche raisonnable pour envoyer une expression à une fonction ; la liste est évaluée... sur la même liste. La fonction travaille sur une copie de la liste.
Arguments de mots clés pour les fonctionsJ'adorerais que dans les fonctions définies par l'utilisateur, nous puissions utiliser des arguments de mots clés dans les appels pour que je puisse le faire
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});
Quelqu'un l'a mentionné ici , mais c'était il y a 8 ans, alors j'ai pensé que j'en reparlerais.
Automatisation et scriptsRe : Arguments de mots-clés pour les fonctions – Statut modifié en : AcquittéRe : Arguments de mots clés pour les fonctionsL'astuce avec la liste est très utile.
En fait, l’évaluation de la liste n’est pas vraiment nécessaire pour accéder aux variables.
On peut parcourir la liste et rechercher le bon nom. soit par une boucle for each, soit via 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});