함수에서 식을 반환하는 것은 네임스페이스가 사용되는 경우와 다릅니다.여러분, 안녕하세요,
함수에서 식을 반환할 때 이상한 동작이 발생했으며 이에 대한 논의를 이미 찾을 수 없었습니다. 저는 거의 모든 것에 네임스페이스를 사용하는 습관이 있습니다. 함수가 표현식을 반환할 때 범위가 지정되지 않은 함수에 대해 표현식이 평가되지 않고 네임스페이스가 사용되는 경우 평가된다는 사실을 발견했습니다. 여기에서 무슨 일이 일어나고 있는지 아는 사람이 있습니까?
이 스크립트는 첫 번째 함수가 호출될 때 변수 x가 증가하지 않고 두 번째 함수 호출에서 증가함을 표시해야 합니다. 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: 네임스페이스를 사용할 때 함수에서 표현식을 반환하는 것이 다릅니다.확실히 버그를 발견한 것 같습니다. 다음은 네임스페이스에서 함수를 사용하는 두 가지 방법에 대한 더욱 단순화된 데모입니다.
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()) = "표현식";
유형(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;
두 가지 문제는 아마도 관련되어 있을 것입니다. 네임스페이스 함수 호출 내부에 지정된 항목은 사용될 때까지 생성되지 않습니다(표현식으로 유지됨). 즉, f1은 네임스페이스가 생성될 때 컴파일되지 않지만 f1은 사용될 때마다 컴파일되므로 속도가 느려집니다.따라서 f1을 다시 컴파일한 다음 이를 평가하는 특수한 C++ 코드가 있을 수 있습니다. 내 생각엔 동일한 코드가 f2에 대해 트리거되지만 f2가 이미 컴파일되었기 때문에 다시 컴파일되지 않고 f2의 결과를 잘못 평가하는데, 이는 대부분의 경우 기본 값이고 아무도 알아차리지 못합니다. 반환된 expr() 값은 더 간단한 값으로 평가되므로 알 수 있습니다.
더보기...
@줄리안 - 이건 버그인 게 확실해요. 잘못된 행동에 따라 네임스페이스 사용자가 많아질 것 같지는 않습니다.
Re: 네임스페이스를 사용하는 경우 함수에서 표현식을 반환하는 방식이 다릅니다.이에 대한 업데이트가 있었나요?
제가 아는 한 이런 현상은 jmp 19에서도 여전히 나타납니다.
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;
다른 누군가가 이 문제를 겪는 경우 빠른 해결 방법은 예시에서 제안한 대로 원하는 결과가 나올 때까지 반환 값을 "Name Expr"로 묶는 것입니다.
작동하지 않습니다. 이전 실행에서 global/here 범위에 ax를 정의해 두었습니다. ns:f2처럼 정의된 함수에서 표현식을 반환할 방법이 없는 것 같습니다.
이건 확실히 버그인 듯합니다. ns:f2가 ns:f1이나 f1과 다른 값을 반환할 거라고 기대하는 사람은 아무도 없을 겁니다. 함수 코드는 정확히 똑같습니다.
Re: 네임스페이스를 사용하는 경우 함수에서 표현식을 반환하는 방식이 다릅니다.지원팀을 통해 보고하겠습니다.
TS-00235798
Re: 네임스페이스를 사용하는 경우 함수에서 표현식을 반환하는 방식이 다릅니다.저도 보고서를 작성했습니다: TS-00235515
지원팀의 답변은 예상치 못한 동작이기는 하지만 버그로 간주되지 않는다는 것이었습니다.
근본 원인은 설명한 대로입니다. 기본적으로 ns:f2 함수가 두 번 평가됩니다.
이는 초기 네임스페이스 생성 외부에서 정의된 모든 것에도 영향을 미치는 것으로 보입니다. 아래의 업데이트된 예에서 볼 수 있습니다.
제안된 솔루션은 모든 것을 표현식으로 묶는 것입니다 - 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))
전체 기능을 만드는 것보다
expr(함수(...
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
이것의 가장 큰 위험은 두 번째 평가가 함수의 로컬 범위 밖에서 발생하는 것처럼 보인다는 것입니다.
전역 변수는 반환 값을 가릴 수 있으며, 이로 인해 오류가 발생하지 않습니다.
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()이라는 이름을 사용하세요.
- 네임스페이스가 반환 값을 "두 번" 평가하지 못하도록 하려면 반환 값을 표현식() 로 보호해야 합니다.
- 이는 Name Expr()의 작업을 어렵게 만듭니다.
Expr(Name Expr())은 Name Expr() 이 작업을 수행하는 것을 중지합니다.
- 이런 경우의 99%에서는 Eval Expr()을 사용할 수 있습니다.
하지만 여기서는 어렵습니다. JMP에서 표현식()은 두 가지 목적으로 사용되기 때문입니다.
- 평가식() 내부에 "it is here()"가 있습니다.
- I protect you() - 네임스페이스 문제에 대한 해결책으로
불행히도 Eval Expr()은 첫 번째 표현식() 에 만족하고 이를 평가할 것입니다.
따라서 Eval Expr(Expr(Expr(Name Expr(x))))는 다음과 같은 방식으로 작동하지 않습니다.
Eval Expr (나는 당신을 보호합니다 (여기에 있습니다(Name Expr(x))))
대신 그것을 다음과 같이 해석합니다.
Eval Expr(여기에 있습니다(나는 당신을 보호합니다(이름 Expr(x))))
그러므로 그것은 돌아올 것이다
Expr(이름 Expr(x))
... 그리고 JMP는 함수 범위 밖에서 x를 검색합니다.
- 모든 표현식 문제에 대한 최종 솔루션은 Substitute() 입니다.
Re: JMP에서의 표현식 처리: Tipps 및 Trapdoors
- is there an easier solution than
Substitute(Expr(Expr(ex)), Expr(ex), (Name Expr(x)))