関数から式を返す方法は、名前空間が使用されている場合とは異なります。こんにちは、みんな、
関数から式を返すときに奇妙な動作に遭遇しましたが、これに関する議論はまだ見つかりませんでした。 私はほとんどすべてのことに名前空間を使用する習慣があります。 関数が式を返す場合、その式はスコープ外の関数については評価されませんが、名前空間が使用されている場合には評価されることがわかりました。 ここで何が起こっているのか知っている人はいますか?
このスクリプトは、最初の関数の呼び出し時に変数 x がインクリメントされず、2 番目の関数呼び出し時にインクリメントされることを示します。 私は JMP v17.0.0 を使用しているため、この問題は修正されている可能性がありますが、現在は更新できません。
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);自動化とスクリプト作成Re: 名前空間を使用する場合、関数から式を返す方法が異なります。17.2.0 に更新しましたが、この問題はまだ発生していることが確認できました。
これは読みやすい簡略化された例です。
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: 名前空間を使用する場合、関数から式を返す方法が異なります。間違いなくバグを発見しました。 以下は、名前空間で関数を使用する 2 つの方法のさらに簡略化されたデモです。
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()) = "式";
Type(funcNS:f2()) = "数値";
f1 は正しい答えを返します。 f2 は答えを誤って評価しています。 私は (このバグを除いて) f2 方法の方が速いので好みます。
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;
この 2 つの問題はおそらく関連しています。 名前空間関数呼び出し内で指定された項目は、使用されるまで構築されません (式として保持されます)。つまり、名前空間の作成時に f1 はコンパイルされませんが、使用されるたびに f1 がコンパイルされるため、処理が遅くなります。したがって、f1 を再コンパイルして評価するための特殊な C++ コードがおそらく存在します。 私の推測では、同じコードが f2 に対してトリガーされますが、f2 はすでにコンパイルされているため再コンパイルされず、f2 の結果が誤って評価されます。これはほとんどの場合プリミティブ値であり、誰も気づきません。 返される expr() 値は、より単純な値に評価されることに注意してください。
もっと見る...
@ジュリアン- 確かにこれはバグです。 間違った動作によっては、名前空間のユーザーが多くなるとは思えません。
Re: 名前空間が使用されている場合、関数から式を返す方法は異なります。これに関して何か更新はありましたか?
私の知る限り、この動作は JMP 19 でもまだ存在しています。
ns:f2 定義では、戻り値が 2 回評価されるように見えます。
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;
もし他の誰かがこの問題に遭遇した場合、簡単な回避策は例に示されているように、戻り値を「Name Expr」で囲むことです。
これはうまくいきません。以前の実行でグローバル/ヒアスコープでaxを定義していました。ns:f2のように定義された関数から式を返す方法はないようです。
これは明らかにバグのようです。ns:f2 が ns:f1 や f1 とは異なる値を返すことを誰も予想していないと思います。関数コードはまったく同じです。
Re: 名前空間が使用されている場合、関数から式を返す方法は異なります。サポートチームを通じて報告します。
TS-00235798
Re: 名前空間が使用されている場合、関数から式を返す方法は異なります。私も報告しました: TS-00235515
サポートからの返答は、動作が予期しないものであったとしても、これはバグとはみなされないというものでした。
根本的な原因はあなたが説明したとおりです。基本的に、ns:f2 関数は 2 回評価されます。
これは、以下の更新された例に見られるように、初期の名前空間の作成外で定義されたすべてのものにも影響するようです。
提案された解決策は、すべてを式で囲むことです - 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) = {"名前が解決されません: a"(1, 2, "a", a /*###*/)};
ns:e3 = 1 + a;
f1() = 1 + 3;
ns:f1() = 1 + 3;
ns:f2() = 4;
ns:f3() = 1 + 3;
Re: 名前空間が使用されている場合、関数から式を返す方法は異なります。この回避策は…残念です。幸いなことに、ほとんどのユーザーは式を返そうとはしていないので、この回避策は必要ありません。
Re: 名前空間が使用されている場合、関数から式を返す方法は異なります。また、不幸な側面のほとんどは、帰国することで軽減される。
式(式(1+1))
関数全体を
式(関数(...
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: 名前空間が使用されている場合、関数から式を返す方法は異なります。この解決策は確かによりエレガントですが、返す式を直接記述できる場合にのみ機能するようです。
式が変数に格納され、それをExpr()でラップすると、返される値は変数名を持つ式になります。
この場合、唯一の解決策は、戻り値をName Expr()でラップし、関数全体をexprでラップすることのようです。
funcNS:f5 = Expr(Function( {}, {Default Local},
x = Expr(1+2);
Name Expr(x)
));
Show( funcNs:f4() ); // 1+2
これに伴う大きな危険の 1 つは、2 回目の評価が関数のローカル スコープ外で行われるように見えることです。
グローバル変数は戻り値を隠してしまう可能性がありますが、その場合エラーは発生しません。
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: 名前空間が使用されている場合、関数から式を返す方法は異なります。おお!
JmpとJSLのTiny Trapsに追加
Re: 名前空間が使用されている場合、関数から式を返す方法は異なります。 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
- 関数内でxを検索する機会を関数に与えます。Expr ()ではなくExpr() という名前を付けます。
- 名前空間が戻り値を「2回」評価するのを防ぐには、戻り値を式()で保護する必要があります。
- これにより、Name Expr() の動作が困難になります。
Expr(Name Expr()) は名前式() の仕事を停止します
- このようなケースの 99% では、 Eval Expr() を使用できます。
しかし、ここでは式()が JMP で 2 つの目的で使用されるため、困難です。
- 式の評価()内の"it is here() "
-私はあなたを守ります() - 名前空間の問題に対する解決策として
残念ながら、 Eval Expr() は最初の式()に満足し、それを評価します。
したがって、 Eval Expr(Expr(Expr(Name Expr(x)))) は、
Eval Expr (私はあなたを守ります (それはここにあります(Name Expr(x))))
代わりに、次のように解釈します
Eval Expr( ここです(私はあなたを守ります(Name Expr(x))))
そしてそれは戻ってくるだろう
Expr(名前Expr(x))
...そしてJMPは関数のスコープ外でxを検索します
- すべての式の問題に対する究極の解決策はSubstitute()です
JMP における式処理: Tipps と Trapdoors
- is there an easier solution than
Substitute(Expr(Expr(ex)), Expr(ex), (Name Expr(x)))