Re: Argumentos de palabras clave para funciones@vince_faller
Genial ejemplo. Gracias por compartir. Corrección de errores tipográficos
show(f(2, {y=14})); // 36 not 33
Re: Argumentos de palabras clave para funciones@gzmorgan0
Creo que robé esto de Hamcrest, pero lo hemos estado usando por un tiempo y en realidad es un método mucho mejor. Todavía puedes hacer algunas cosas malas, pero se comprueba un poco mejor.
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: Argumentos de palabras clave para funciones@gzmorgan0 Mi mayor problema con la lista de kwargs es que permite ejecutar cualquier cosa. Por ejemplo, si quiero ver todos los locales en una función determinada.
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)});
Lo cual es un problema de seguridad para mí con el código encriptado.
De hecho, mantengo las cosas en una matriz asociativa y luego hago una intersección << con una matriz asociativa predeterminada para verificar que los argumentos pasados son válidos.
Luego analizo los pares de valores clave en la función para no tener que usar la matriz para llamarlos.
Tengo funciones de ayuda para hacer todo esto, pero eso trae su propio conjunto de problemas.Y es más engorroso de lo que me gusta.
@xangregg , mi error.Tengo un campo de visión mucho más estrecho en la mayoría de estas cosas.
Re: Argumentos de palabras clave para funciones@vince_faller , todavía me gusta la solución kwargs={} propuesta con una modificación.IMHO Default Local es bueno para secuencias de comandos simples, pero es arriesgado para secuencias de comandos complejas.Recomiendo manejar una lista de variables locales. De todos modos, a continuación hay un script que es una modificación de su solución kwargs, pero usa la sintaxis, {z,4} vs. z=4 como elementos en su lista de kwargs y requiere un bloque de código que puede ser genérico. Una función podría usar una matriz asociativa local para asignar valores de "palabra clave" que implicarían el bloque de código que se indica a continuación, sin embargo, entonces la sintaxis de la variable individual es más engorrosa, en lugar de a+b sería algo así como aa1[a] + aa1[b], por lo que el ejemplo usa listas.
si tuviera una función con muchas variables, pero para cada llamada de función quisiera cambiar solo algunas, podría usar este enfoque. La clave aquí es que
- ninguna variable se cambia a menos que esté en varList, y
- los valores modificados son 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: Argumentos de palabras clave para funcionesDerecho. Lo crea o no, tratamos de no romper los viejos comportamientos de JSL, incluso los poco probables.:)
Re: Argumentos de palabras clave para funcionesAh.Entonces, si alguien usara esa sintaxis (por cualquier motivo), se rompería si necesitara az global más adelante.Entendido.
Re: Argumentos de palabras clave para funcionesActualmente se evalúan los argumentos de las funciones de usuario y z=4 es una expresión válida, por lo que
f(1, z=4);
evaluaría z=4, creando una z global y teniendo un resultado de 4, y luego pasaría el resultado al argumento y de f.
Re: Argumentos de palabras clave para funciones¿Por qué sería necesaria una nueva sintaxis?¿Estás diciendo por llamar o por definir?Creo que podríamos definirlos de la misma manera.
Si una función ya no usa argumentos de palabras clave, usará de forma predeterminada argumentos posicionales como lo hace actualmente.
Obviamente, no podríamos usar argumentos de palabras clave antes de que se implementen, por lo que no veo que eso rompa los scripts.
La función
f = function({x, y=2, z=3},
show(x, y, z);
);
no rompería ningún otro script.
y si todos los scripts anteriores usan argumentos posicionales de todos modos, entonces no creo que rompa nada.
Pero si hubiera argumentos de palabras clave que por defecto fueran posicionales si no se especificaron palabras clave, haciendo
f(1, 2, 4);
no rompería nada (supongo). Pero solo permitiría
f(1, z=4);
No veo por qué necesitaría un espacio de nombres falso (pero, de nuevo, no entiendo cómo funcionan las funciones debajo del capó).
Re: Argumentos de palabras clave para funcionesEsto necesitaría una nueva sintaxis que no cambiaría los scripts existentes. Tal vez algo como su ejemplo con una lista que se pasa a un receptor especial. O tal vez una nueva sintaxis en la persona que llama, como un espacio de nombres falso: f(1, arg:z = 2).
Re: Argumentos de palabras clave para funcionesGracias.Definitivamente tiene algunos problemas. El más grande probablemente sea capaz de inyectar cualquier variable en una función y, a menudo, causa una colisión de variables. No tengo cuidado.
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: Argumentos de palabras clave para funcionesSu solución actual de lista de "kwargs" es un buen truco provisional.
Re: Argumentos de palabras clave para funciones¿Cómo se definen las funciones Jmp estándar,
- tal que cerca acepta un argumento suplementario noGuardar .
- tal que add column acepte la expresión Formula(...) en cualquier posición dentro de (...)
dt << New Column( "X", Formula( row() ) );
En lugar de
f(2, {y=14})podría
f(2, y(14))
ser la forma en que debería verse?
Re: Argumentos de palabras clave para funcionesLas funciones internas están construidas en C++, no en JSL. Las funciones de usuario (en JSL) son interpretadas por otro código C++ que elige cómo convertir los argumentos en parámetros (donde los argumentos de una función son los valores externos pasados y los parámetros de la función son los nombres de las variables internas que se refieren a los valores).
Una función como sin(A), escrita en C++, se parece a
ExpressionPointer sin( ExpressionPointer E) {
double value = evaluateExpression( E );
double answer = sin( value );
return makeExpression( answer );
}
La función expr() en JSL, donde la función simplemente devuelve su argumento sin estudiarlo, se parece a
ExpressionPointer expr( ExpressionPtr E ) {
return E;
}
Eso parece inútil a primera vista, pero permite que el operador de asignación evalúe el lado derecho de
ex = expr( a + b );
y almacene un árbol de expresión en ex en lugar del resultado de a+b. Un ejemplo más interesante es el operador head(a+b).
ExpressionPointer head( ExpressionPointer E ) {
return MakeExpression( E->child );
}
Esa es una aproximación cruda de la idea: un árbol de expresión para a+b tiene una raíz, +, que tiene dos hijos, a y b.E->child obtiene la raíz, +, y la devuelve como una expresión sin hijos.
Los desarrolladores de JMP tomaron la decisión de ocultar esa complejidad en las funciones escritas por el usuario de JSL para que el 99 % de los casos de uso fueran fáciles de escribir. La mayoría de los lenguajes con los que estoy familiarizado no tienen expresiones que puedan manipularse (Snobol las tiene, más o menos, y eso explica la función patmatch() de JMP...) Usar una lista es un enfoque razonable para enviar una expresión a una función; la lista se evalúa... a la misma lista. La función está trabajando en una copia de la lista.
Argumentos de palabras clave para funcionesMe encantaría si en las funciones definidas por el usuario pudiéramos usar argumentos de palabras clave en las llamadas para poder hacer
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});
Alguien lo mencionó aquí , pero fue hace 8 años, así que pensé en volver a mencionarlo.
Automatización y secuencias de comandosRe: Argumentos de palabras clave para funciones - Estado cambiado a: ReconocidoRe: Argumentos de palabras clave para funcionesEl truco de la lista es muy útil.
En realidad, no es necesario evaluar la lista para acceder a las variables.
Se puede escanear la lista y buscar el nombre correcto. ya sea mediante un bucle para cada bucle o mediante 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});