回复:函數的關鍵字參數@vince_faller
很酷的例子。 感謝分享。 錯別字更正
show(f(2, {y=14})); // 36 not 33
回复:函數的關鍵字參數@gzmorgan0
我想我是從 hamcrest 那裡偷來的,但我們已經使用了一段時間,實際上這是一種更好的方法。 您仍然可以做一些壞事,但它會檢查得更好一些。
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
回复:函數的關鍵字參數@gzmorgan0我對 kwargs 列表最大的問題是它允許執行任何東西。 例如,如果我想查看給定函數中的所有局部變量。
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)});
這對我來說是加密代碼的安全問題。
我實際上將內容保存在關聯數組中,然後執行 << 與默認關聯數組相交以檢查傳遞的參數是否有效。
然後我只是將鍵值對解析到函數中,這樣我就不必使用數組來調用它們了。
我有幫助功能來完成所有這些,但這會帶來一系列問題。而且它比我喜歡的更麻煩。
@XanGregg , 我的錯。我對這些事情中的大多數都有更狹窄的視野。
回复:函數的關鍵字參數@vince_faller ,我仍然喜歡你提出的 kwargs={} 修改後的解決方案。恕我直言,Default Local 非常適合簡單的腳本編寫,但對於復雜的腳本來說是有風險的。我建議管理局部變量列表。 無論如何,下面是一個腳本,它是對您的 kwargs 解決方案的修改,但使用語法 {z,4} vs. z=4 作為您的 kwargs 列表中的項目,並且需要一個可以通用的代碼塊。 一個函數可以使用局部關聯數組來分配“關鍵字”值,這將隱含下面提到的代碼塊,但是,單個變量語法更麻煩,而不是 a+b 它將類似於 aa1[a] + aa1[b],所以這個例子使用列表。
如果我有一個包含許多變量的函數,但對於每個函數調用只想更改幾個變量,我可能會使用這種方法。 這裡的關鍵是
- 除非變量在 varList 中,否則不會更改任何變量,並且
- 更改的值是本地的。
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});
回复:函數的關鍵字參數正確的。 信不信由你,我們盡量不破壞舊的 JSL 行為,即使是不太可能的行為。:)
回复:函數的關鍵字參數啊。因此,如果有人使用該語法(無論出於何種原因),如果他們以後需要 az global,它就會中斷。知道了。
回复:函數的關鍵字參數當前評估用戶函數的參數並且 z=4 是一個有效的表達式,所以
f(1, z=4);
將計算 z=4,創建一個全局 z 並得到 4 的結果,然後將結果傳遞給 f 的 y 參數。
回复:函數的關鍵字參數為什麼需要新語法?你是說呼喚還是定義?我認為我們可以用同樣的方式來定義它們。
如果一個函數已經不使用關鍵字參數,那麼它會像現在一樣默認使用位置參數。
顯然我們不能在實現之前使用關鍵字參數,所以我不認為這是破壞腳本。
功能
f = function({x, y=2, z=3},
show(x, y, z);
);
不會破壞任何其他腳本。
如果所有以前的腳本都使用位置參數,那麼我認為它不會破壞任何東西。
但是如果我有關鍵字參數,如果沒有指定關鍵字則默認為位置,做
f(1, 2, 4);
不會破壞任何東西(我猜)。 但它只會讓
f(1, z=4);
我不明白為什麼它需要一個假的命名空間(但話又說回來我不明白函數是如何工作的)。
回复:函數的關鍵字參數這將需要一種不會更改現有腳本的新語法。 也許像您的示例一樣,將列表傳遞給特殊的接收者。 或者可能是調用者的新語法,例如假命名空間:f(1, arg:z = 2)。
回复:函數的關鍵字參數謝謝。它肯定有一些問題。 最大的可能是能夠將任何變量注入函數並且經常導致變量衝突我不小心。
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});
回复:函數的關鍵字參數您當前的“kwargs”列表解決方案是一個很好的臨時技巧。
回复:函數的關鍵字參數標準 Jmp 函數是如何定義的,
- 這樣關閉接受補充論證不保存。
- 這樣添加列在 (...) 內的任何位置接受表達式 Formula(...)
dt << New Column( "X", Formula( row() ) );
代替
f(2, {y=14})可以
f(2, y(14))
應該是什麼樣子?
回复:函數的關鍵字參數內部函數是用 C++ 構建的,而不是 JSL。 用戶函數(在 JSL 中)由其他 C++ 代碼解釋,這些代碼選擇如何將自變量轉換為參數(其中函數的自變量是傳入的外部值,函數的參數是引用這些值的內部變量名稱。)
像 sin(A) 這樣的函數,用 C++ 編寫,看起來像
ExpressionPointer sin( ExpressionPointer E) {
double value = evaluateExpression( E );
double answer = sin( value );
return makeExpression( answer );
}
JSL 中的 expr() 函數僅返回其參數而不對其進行研究,看起來類似於
ExpressionPointer expr( ExpressionPtr E ) {
return E;
}
乍一看這似乎沒什麼用,但它允許賦值運算符評估右側
ex = expr( a + b );
並將表達式樹存儲到 ex 而不是 a+b 的結果中。 一個更有趣的例子是 head(a+b) 運算符。
ExpressionPointer head( ExpressionPointer E ) {
return MakeExpression( E->child );
}
這是這個想法的粗略近似:a+b 的表達式樹有一個根 +,它有兩個子節點 a 和 b。E->child 獲取根+,並將其作為沒有子項的表達式返回。
JMP 開發人員決定在 JSL 用戶編寫的函數中隱藏這種複雜性,以使 99% 的用例易於編寫。 我熟悉的大多數語言都沒有可操作的表達式(Snobol 有某種程度的表達式,這解釋了 JMP 的 patmatch() 函數...) 使用列表是將表達式發送到函數的合理方法;該列表被評估...到同一個列表。 該函數正在處理列表的副本。
函數的關鍵字參數如果在用戶定義的函數中我們可以在調用中使用關鍵字參數,我會很高興,這樣我就可以做到
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});
有人提到過這裡,但那是8年前的事了,所以我想我會再次提起它。
自動化和腳本編寫回覆:函數的關鍵字參數 - 狀態變更為:已確認回覆:函數的關鍵字參數清單的技巧非常有用。
實際上,訪問變數並不真正需要評估清單。
人們可以掃描列表並蒐索正確的名稱。透過 foreach 循環或透過 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});