La restituzione di un'espressione da una funzione differisce quando viene utilizzato lo spazio dei nomi.Ciao a tutti,
Mi sono imbattuto in uno strano comportamento durante la restituzione di un'espressione da una funzione e non sono riuscito a trovare già alcuna discussione al riguardo. Ho l'abitudine di usare gli spazi dei nomi praticamente per tutto. Ho scoperto che quando una funzione restituisce un'espressione, l'espressione non viene valutata per una funzione senza ambito, ma viene valutata se viene utilizzato uno spazio dei nomi. Qualcuno sa cosa sta succedendo qui?
Questo script dovrebbe mostrare che la variabile x non viene incrementata quando viene chiamata la prima funzione, ma viene incrementata alla seconda chiamata di funzione. Sto utilizzando JMP v17.0.0, quindi probabilmente è stato risolto, ma al momento non sono in grado di eseguire l'aggiornamento.
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);Automazione e scriptingRe: La restituzione di un'espressione da una funzione differisce quando viene utilizzato lo spazio dei nomi.Ho aggiornato alla versione 17.2.0 e posso confermare che il problema persiste.
Ecco un esempio semplificato che, si spera, dovrebbe essere più facile da leggere
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;Ri: La restituzione di un'espressione da una funzione differisce quando viene utilizzato lo spazio dei nomi.Sono abbastanza sicuro di aver scoperto un bug. Ecco una demo ancora più semplificata di due modi per utilizzare le funzioni negli spazi dei nomi:
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()) = "Espressione";
Tipo(funcNS:f2()) = "Numero";
f1 restituisce la risposta corretta; f2 valuta erroneamente la risposta. Preferisco il metodo f2 (a parte questo bug) perché è più veloce:
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;
Probabilmente le due questioni sono correlate. Gli elementi specificati all'interno della chiamata alla funzione dello spazio dei nomi non vengono costruiti finché non vengono utilizzati (vengono mantenuti come espressioni). Ciò significa che f1 non viene compilato quando viene creato lo spazio dei nomi, ma f1 viene compilato ogni volta che viene utilizzato, quindi più lentamente.Quindi probabilmente c'è del codice C++ specializzato per ricompilare f1 e quindi valutarlo. La mia ipotesi è che lo stesso codice venga attivato per f2, ma non si ricompili perché f2 è già compilato e quindi valuta erroneamente il risultato di f2, che la maggior parte delle volte è un valore primitivo e nessuno se ne accorge. Il valore expr() restituito viene valutato in un valore più semplice, facendotelo notare.
Visualizza altro...
@giuliano - sono abbastanza sicuro che si tratti di un bug. Non penso che ci saranno molti utenti dello spazio dei nomi a seconda del comportamento sbagliato.
Re: La restituzione di un'espressione da una funzione è diversa quando viene utilizzato lo spazio dei nomi.Ci sono stati aggiornamenti a riguardo?
Per quanto ne so, questo comportamento esiste ancora in jmp 19.
Sembra proprio che il valore di ritorno venga valutato due volte nella definizione 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;
Se qualcun altro riscontra questo problema, la soluzione rapida è quella suggerita nell'esempio: racchiudere il valore restituito in "Name Expr" fino al risultato desiderato.
Questo non funziona. Avevo definito ax nell'ambito globale/here da esecuzioni precedenti. Sembra che non ci sia modo di restituire un'espressione da una funzione definita come ns:f2.
Questo sembra decisamente un bug, non credo che qualcuno si aspetterebbe che ns:f2 restituisca un valore diverso rispetto a ns:f1 o f1; il codice della funzione è esattamente lo stesso.
Re: La restituzione di un'espressione da una funzione è diversa quando viene utilizzato lo spazio dei nomi.Farò una segnalazione al team di supporto.
Codice articolo: TS-00235798
Re: La restituzione di un'espressione da una funzione è diversa quando viene utilizzato lo spazio dei nomi.Ho anche fatto un rapporto: TS-00235515
La risposta dell'assistenza è stata che questo non era considerato un bug, anche se il comportamento era inaspettato.
La causa principale era quella che hai descritto; in pratica la funzione ns:f2 viene valutata due volte.
Ciò sembra influenzare anche tutto ciò che è definito al di fuori della creazione iniziale dello spazio dei nomi, come si può vedere nell'esempio aggiornato di seguito.
La soluzione proposta è quella di racchiudere tutto in un'espressione: 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) = {"Nome non risolto: 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 restituzione di un'espressione da una funzione è diversa quando viene utilizzato lo spazio dei nomi.Questa soluzione alternativa è... sfortunata. Fortunatamente, la maggior parte degli utenti non cerca di restituire espressioni e non ne ha bisogno.
Re: La restituzione di un'espressione da una funzione è diversa quando viene utilizzato lo spazio dei nomi.Inoltre, la maggior parte degli aspetti spiacevoli possono essere alleviati tornando
espr(espr(1+1))
piuttosto che rendere l'intera funzione
expr(funzione(...
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 restituzione di un'espressione da una funzione è diversa quando viene utilizzato lo spazio dei nomi.Questa soluzione è in effetti più elegante, tuttavia sembra funzionare solo quando è possibile scrivere direttamente l'espressione da restituire.
Se l'espressione è memorizzata in una variabile e la racchiudiamo in un Expr(), il valore restituito è un'espressione con il nome della variabile
In questo caso sembra che l'unica soluzione sia quella di racchiudere il valore di ritorno in un Name Expr() e l'intera funzione in un expr
funcNS:f5 = Expr(Function( {}, {Default Local},
x = Expr(1+2);
Name Expr(x)
));
Show( funcNs:f4() ); // 1+2
Un grosso pericolo è che la seconda valutazione sembra avvenire al di fuori dell'ambito locale della funzione.
Una variabile globale potrebbe oscurare il valore restituito, il che non genererebbe alcun errore.
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 restituzione di un'espressione da una funzione è diversa quando viene utilizzato lo spazio dei nomi.Oh!
aggiunto a Tiny Traps in Jmp e JSL
Re: La restituzione di un'espressione da una funzione è diversa quando viene utilizzato lo spazio dei nomi. 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
- dare alla funzione la possibilità di cercare x all'interno della funzione: chiamare Expr() invece di Espr().
- per impedire che lo spazio dei nomi valuti il valore di ritorno "due volte", il valore di ritorno deve essere protetto con Espr()
- questo rende la vita difficile al Name Expr()
Expr(Nome Expr()) impedirà a Nome Expr() di svolgere il suo lavoro
- Nel 99% di questi casi è possibile utilizzare Valuta Expr().
Ma qui è difficile, perché Espr() viene utilizzato in JMP per 2 scopi:
- "è qui()" all'interno di Valutazione Expr()
- Ti proteggo() - come soluzione al problema dello spazio dei nomi
sfortunatamente, Valutazione Expr() si accontenterà del primo Espr() e lo valuterà.
quindi, Eval Expr(Expr(Expr(Nome Expr(x)))) non funzionerà nello spirito di
Eval Expr (Ti proteggo (è qui(Nome Expr(x))))
invece lo interpreta come
Eval Expr( è qui(ti proteggo(nome Expr(x))))
e quindi ritornerà
Espr(Nome Espr(x))
... e quindi JMP cercherà x al di fuori dell'ambito della funzione
- La soluzione definitiva a tutti i problemi di espressione è Substitute()
Re: Gestione delle espressioni in JMP: Tipps e Trapdoor
- is there an easier solution than
Substitute(Expr(Expr(ex)), Expr(ex), (Name Expr(x)))