在函数中,我正在执行以下操作:
{3#x} each 7,8,9
/ returns (7 7 7j;8 8 8j;9 9 9j)
以下代码失败(据我了解,因为N
在lambda中未定义):
foo:{
N: floor acos -1;
{N#x} each x }
foo 7,8,9
我的解决方法是使用投影:
foo:{
N: floor acos -1;
{y#x}[;N] each x }
有没有更短或更整洁的解决方案?
答案 0 :(得分:2)
内部函数无权访问父函数变量。您需要将所需的父变量显式传递给内部函数。
在您的示例中,可以通过将代码更改为使用“#”和each-both来避免内部lambda函数:
q) foo:{#'[floor acos -1;x]}
q) foo 7 8 9
7 7 7
8 8 8
9 9 9
提示:始终先尝试使用KDB运算符和副词实现逻辑。可以通过多种方式将它们组合在一起,以生成高效且简单的代码。
答案 1 :(得分:2)
我认为问题是由于q / kdb中缺少所谓的“词法作用域”而引起的。这本质上意味着局部变量在同一范围内定义的局部函数的主体内不可见。此处的内部功能无法在定义位置的位置“看到”N。
以下也许是一种更为简洁的方法
{(floor acos -1)#'x}[7 8 9]
否则,当您将局部变量作为参数传递时,您的解决方法就可以正常工作。注意,您正在尝试将“ take”运算符应用于正确的每个参数,因此可以略微加速,因此您可以将“ each right”运算符/:......
q)\t:1000000 N:floor acos -1;f:{[N;x] N#/:x};f[N;7 8 9]
1308
q)\t:1000000 N:floor acos -1;{y#x}[;N]each 7 8 9
1835
这可以通过使用“ each both”运算符来进一步优化,该运算符将成对评估take运算符的两个参数,并扩展一个原子参数以匹配列表的长度。
这是Rahuls示例中发生的事情:
q)\t:1000000 foo:{#'[floor acos -1;x]};foo 7 8 9
1012
希望这会有所帮助。
答案 2 :(得分:2)
如Rahul和Liam所述,对于这个简单的示例,最好的方法是take
和each-both
方法。
在某些情况下,可以使用括号()
创建简单的投影,同时保持相同的可读性。在您的示例中:
q){N:floor acos -1;(N#)each x}7 8 9
7 7 7
8 8 8
9 9 9
关于变量作用域-非全局变量仅在函数的大括号{}
中限定范围
答案 3 :(得分:-1)
要完全避免使用lambda,可以采用以下解决方案(基于Liam上面提供的解决方案):
(#[floor acos -1] @)each 7 8 9
此格式可以帮助避免词汇作用域问题,因为它可以访问括号本身内括号之外的变量。等效的语句为:
N: floor acos -1; (#[N]@) each 7 8 9
一个人可以像在一个函数中一样操作括号中的结果(因为它在括号中被“功能化”,以告知解释者适当的“动作”顺序)
N: floor acos -1; (1_ #[N]@) each 7 8 9