回复:函数的关键字参数@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年前的事了,所以我想我会再次提起它。
自动化和脚本编写回复:函数的关键字参数 - 状态更改为:已确认回复:函数的关键字参数这个列表的技巧非常有用。
实际上,访问变量并不需要真正评估列表。
可以扫描列表并搜索正确的名称。可以通过每个循环或通过 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});