Devolver una expresión de una función difiere cuando se usa el espacio de nombres.Hola a todos,
Me encontré con un comportamiento extraño al devolver una expresión de una función, y ya no pude encontrar ninguna discusión sobre esto. Tengo la costumbre de usar espacios de nombres para casi todo. Descubrí que cuando una función devuelve una expresión, la expresión no se evalúa para una función sin ámbito, pero se evalúa si se usa un espacio de nombres. ¿Alguien sabe lo que está pasando aquí?
Este script debería mostrar que la variable x no se incrementa cuando se llama a la primera función, sino que se incrementa en la segunda llamada de función. Estoy usando JMP v17.0.0, por lo que posiblemente se haya solucionado, pero no puedo actualizar en este momento.
NewNamespace("varNamespace");
varNamespace:x = 0;<BR />
myFunc = Function({},
{DEFAULTLOCAL},
returnVal = Expr(varNamespace:x++);
NameExpr(returnVal);
);
myFunc();
Show(varNamespace:x);
NewNamespace("functionTest");
functionTest:myFunc = Function({},
{DEFAULTLOCAL},
returnVal = Expr(varNamespace:x++);
NameExpr(returnVal);
);
functionTest:myFunc();
show(varNamespace:x);Automatización y secuencias de comandosRe: La devolución de una expresión de una función difiere cuando se utiliza el espacio de nombres.Actualicé a 17.2.0 y puedo confirmar que el problema persiste.
Aquí hay un ejemplo simplificado que, con suerte, debería ser más fácil de leer.
x = 0;
myFunc = Function({}, {DEFAULTLOCAL},
Expr(::x++);
);
myFunc(); // Returns unevaluated expression: Expr(::x++)
Show(::x); // ::x=0;
NewNamespace("funcNS");
funcNS:myFunc = Function({},{DEFAULTLOCAL},
Expr(::x++);
);
funcNS:myFunc(); // Returns evaluated expression;
show(::x); // ::x=1;Re: La devolución de una expresión de una función difiere cuando se utiliza el espacio de nombres.Estoy bastante seguro de que has descubierto un error. Aquí hay una demostración aún más simplificada de dos formas de usar funciones en espacios de nombres:
funcNS = New Namespace(
"funcNS",
f1 = Function( {},
expr(1+2)
)
);
funcNS:f2 = Function( {},
expr(1+2)
);
Show( Type( funcNS:f1() ), Type( funcNS:f2() ) );
Type(funcNS:f1()) = "Expresión";
Tipo(funcNS:f2()) = "Número";
f1 devuelve la respuesta correcta; f2 está evaluando incorrectamente la respuesta. Prefiero la forma f2 (excepto por este error) porque es más rápida:
funcNS = New Namespace(
"funcNS",
f1 = Function( {},
1
)
);
funcNS:f2 = Function( {},
1
);
nf1 = 0;
For( endtime = HP Time() + 1e6, endtime > HP Time(), nf1++,
funcNS:f1()
);
Show( nf1 ); // 180K calls
nf2 = 0;
For( endtime = HP Time() + 1e6, endtime > HP Time(), nf2++,
funcNS:f2()
);
Show( nf2 ); // 260K calls
nf1 = 182239;
nf2 = 258929;
Probablemente las dos cuestiones estén relacionadas. Los elementos especificados dentro de la llamada a la función del espacio de nombres no se construyen hasta que se usan (se mantienen como expresiones). Eso significa que f1 no se compila cuando se crea el espacio de nombres, pero f1 se compila cada vez que se usa, por lo que es más lento.Entonces, probablemente haya algún código C++ especializado para recompilar f1 y luego evaluarlo. Supongo que el mismo código se activa para f2, pero no se vuelve a compilar porque f2 ya está compilado y luego evalúa incorrectamente el resultado de f2, que la mayoría de las veces es un valor primitivo y nadie se da cuenta. El valor expr() que se devuelve se evalúa como un valor más simple, lo que hace que lo notes.
Ver más...
@Julian - Estoy bastante seguro de que esto es un error. No creo que haya muchos usuarios de espacios de nombres que dependan del comportamiento incorrecto.
Re: La devolución de una expresión desde una función difiere cuando se utiliza el espacio de nombres.¿Ha habido alguna actualización sobre esto?
Hasta donde puedo decir, este comportamiento todavía existe en jmp 19.
Definitivamente parece que el valor de retorno se evalúa dos veces en la definición de ns:f2:
ns = New Namespace("fns",
f1 = Function({},
x = Expr(1+3);
return(Name Expr(x));
);
);
f1 = Function({},
x = Expr(1+3);
return(Name Expr(x));
);
ns:f2 = Function({},
x = Expr(1+3);
return(Name Expr(x));
);
ns:f3 = Function({},
x = Expr(1+3);
return(Name Expr(Name Expr(x)));
);
Show(f1(), ns:f1(), ns:f2(), ns:f3());
f1() = 1 + 3;
ns:f1() = 1 + 3;
ns:f2() = 4;
ns:f3() = 1 + 3;
f1() = 1 + 3;
ns:f1() = 1 + 3;
ns:f2() = 4;
ns:f3() = x;
Si alguien más se encuentra con este problema, la solución rápida es la que sugiere el ejemplo: envuelva el valor de retorno en "Nombre Expr" hasta obtener el resultado deseado.
Esto no funciona. Tenía ax definido en el ámbito global/aquí de ejecuciones anteriores. Parece que no hay forma de devolver una expresión de una función definida como ns:f2.
Esto definitivamente parece un error, no creo que nadie esperaría que un ns:f2 devolviera un valor diferente en comparación con ns:f1 o f1; el código de función es exactamente el mismo.
Re: La devolución de una expresión desde una función difiere cuando se utiliza el espacio de nombres.Haré un informe a través del equipo de soporte.
TS-00235798
Re: La devolución de una expresión desde una función difiere cuando se utiliza el espacio de nombres.También hice un informe: TS-00235515
La respuesta del soporte fue que esto no se consideraba un error, incluso si el comportamiento era inesperado.
La causa raíz fue la que usted describió: básicamente, la función ns:f2 se evalúa dos veces.
Esto también parece afectar a todo lo definido fuera de la creación del espacio de nombres inicial, como se puede ver en el ejemplo actualizado a continuación.
La solución propuesta es envolver todo en una expresión: ns:f2 = Expr(Function(....))
Names Default to Here(1);
delete symbols();
ns = New Namespace("fns",
{
f1 = Function({},{Default Local},
x = Expr(1+3);
return(Name Expr(x));
),
e1 = Name Expr(expr(1 + a))
}
);
f1 = Function({},{Default Local},
x = Expr(1+3);
return(Name Expr(x));
);
ns:f2 = Function({},{Default Local},
x = Expr(1+3);
return(Name Expr(x));
);
ns:f3 = Expr(Function({},{Default Local},
x = Expr(1+3);
return(Name Expr(x));
));
ns:e2 = Name Expr(expr(1 + a));
ns:e3 = Expr(Name Expr(expr(1 + a)));
show(ns:e1);
show(try(ns:e2, exception_msg));
show(ns:e3);
Show(f1(), ns:f1(), ns:f2(), ns:f3());
ns:e1 = 1 + a;
Try(ns:e2, exception_msg) = {"Nombre sin resolver: a"(1, 2, "a", a /*###*/)};
ns:e3 = 1 + a;
f1() = 1 + 3;
ns:f1() = 1 + 3;
ns:f2() = 4;
ns:f3() = 1 + 3;
Re: La devolución de una expresión desde una función difiere cuando se utiliza el espacio de nombres.Esa solución alternativa es... desafortunada. Afortunadamente, la mayoría de los usuarios no intentan devolver expresiones y no la necesitan.
Re: La devolución de una expresión desde una función difiere cuando se utiliza el espacio de nombres.Además, la mayor parte de los aspectos desafortunados se pueden aliviar volviendo
expr(expr(1+1))
en lugar de hacer que toda la función sea
expr(función(...
funcNS = New Namespace(
"funcNS",
f1 = Function( {},
expr(1+2)
)
);
funcNS:f2 = Function( {},
expr(expr(1+2)) // <<<< extra expr wrapper
);
Show( Type( funcNS:f1() ), Type( funcNS:f2() ) ); // expr, expr
Re: La devolución de una expresión desde una función difiere cuando se utiliza el espacio de nombres.Esa solución es de hecho más elegante, sin embargo parece funcionar sólo cuando puedes escribir directamente la expresión a devolver.
Si la expresión se almacena en una variable y la envolvemos en un Expr() el valor devuelto es una expresión con el nombre de la variable
En este caso, parece que la única solución es envolver el valor de retorno en un Name Expr() y la función completa en un expr
funcNS:f5 = Expr(Function( {}, {Default Local},
x = Expr(1+2);
Name Expr(x)
));
Show( funcNs:f4() ); // 1+2
Un gran peligro con esto es que la segunda evaluación parezca ocurrir fuera del alcance local de la función.
Una variable global podría ocultar el valor de retorno, lo que no generaría un error.
Names Default to Here(1);
Delete Symbols(); // Only use if you dont have variables you need
funcNS = New Namespace("funcNS");
funcNS:f1 = Function( {}, {Default Local},
x = Expr(1+2);
Expr(x);
);
funcNS:f2 = Function( {}, {Default Local},
x = Expr(1+2);
Expr(Expr(x));
);
funcNS:f3 = Expr(Function( {}, {Default Local},
x = Expr(1+2);
x;
));
funcNS:f4 = Expr(Function( {}, {Default Local},
x = Expr(1+2);
Expr(x);
));
funcNS:f5 = Expr(Function( {}, {Default Local},
x = Expr(1+2);
Name Expr(x)
));
Show( Try(funcNs:f1(), exception_msg) ); // Name Unresolved
Show(funcNs:f2()); // X
Show(funcNs:f3()); // 3
Show(funcNs:f4()); // x
Show(funcNs:f5()); // 1+2
// Second Evaluation happens outside Function scope
x = Expr(Expr(1+10));
Show(funcNs:f1()); // 1+10
Re: La devolución de una expresión desde una función difiere cuando se utiliza el espacio de nombres.¡Guau!
añadido a Tiny Traps en Jmp y JSL
Re: La devolución de una expresión desde una función difiere cuando se utiliza el espacio de nombres. Names Default to Here(1);
x= Expr("Hello");
funcNS = New Namespace("funcNS");
funcNS:f = Function( {}, {Default Local},
x = Expr(1+2);
Substitute(Expr(Expr(ex)), Expr(ex), (Name Expr(x)))
);
Show( funcNS:f() , Type( funcNS:f() ) ); // expr, expr
- Dale a la función la oportunidad de buscar x dentro de la función: Nombra Expr() en lugar de Expr().
- Para evitar que el espacio de nombres evalúe el valor de retorno "dos veces", el valor de retorno debe protegerse con Expr()
- Esto le dificulta la vida al Nombre Expr()
Expr(Nombre Expr()) evitará que Nombre Expr() haga su trabajo
- En el 99% de estos casos, se puede utilizar Eval Expr().
Pero aquí es difícil, porque Expr() se utiliza en JMP para dos propósitos:
- "está aquí()" dentro de Eval Expr()
- Te protejo() - como solución al problema del espacio de nombres
Desafortunadamente, Eval Expr() estará satisfecho con el primer Expr() y lo evaluará.
Por lo tanto, Eval Expr(Expr(Expr(Nombre Expr(x)))) no funcionará en el espíritu de
Eval Expr (Te protejo (está aquí(Nombre Expr(x))))
En cambio, lo interpreta como
Eval Expr(está aquí(te protejo(nombre Expr(x))))
y por lo tanto volverá
Expr(Nombre Expr(x))
... y luego JMP buscará x fuera del alcance de la función
- La solución definitiva a todos los problemas de expresión es Substitute()
Re: Manejo de expresiones en JMP: Consejos y trampas
- is there an easier solution than
Substitute(Expr(Expr(ex)), Expr(ex), (Name Expr(x)))