в функции, как передать значение встроенной подфункции - PullRequest
0 голосов
/ 28 января 2019

В функции я делаю что-то вроде этого:

{3#x} each 7,8,9
/ returns (7 7 7j;8 8 8j;9 9 9j)

Следующий код завершается ошибкой (насколько я понимаю, потому что N не определен в лямбде):

foo:{
    N: floor acos -1; 
    {N#x} each x  }
foo 7,8,9

Мой обходной путь - использовать проекцию:

foo:{
  N: floor acos -1; 
  {y#x}[;N] each x  }

Есть ли более короткое или аккуратное решение?

Ответы [ 4 ]

0 голосов
/ 28 января 2019

Чтобы вообще не использовать лямбды, можно принять следующее решение (на основе решения, предоставленного Лиамом выше):

(#[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

0 голосов
/ 28 января 2019

Я думаю, что проблема возникает из-за отсутствия так называемого «лексического определения» в q / kdb.По сути, это означает, что локальная переменная не видна в теле локальной функции, определенной в той же области видимости.Внутренняя функция здесь не может «видеть» N там, где вы ее определили.

Возможно, более кратким подходом будет следующий

{(floor acos -1)#'x}[7 8 9]

В противном случае ваш обходной путь работает просто отлично, когда вы передаете локальную переменную в качестве аргумента.Это можно немного ускорить, заметив, что вы пытаетесь применить оператор «take» к каждому из аргументов справа, поэтому вы можете применить оператор «каждое право» /:...

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 попарно, расширяя аргумент atom для соответствия длине списка.

Это то, чтов примере с Рахулсом:

q)\t:1000000 foo:{#'[floor acos -1;x]};foo 7 8 9
1012

Надеюсь, это поможет.

0 голосов
/ 28 января 2019

Как уже упоминали Рахул и Лиам, лучший подход - это подход take и each-both для этого простого примера.

Есть также случаи, когда создание простой проекции с использованием скобок () может работать при сохранении той же разборчивости.В вашем примере:

q){N:floor acos -1;(N#)each x}7 8 9
7 7 7
8 8 8
9 9 9

Что касается области видимости переменных - неглобальные переменные находятся только в скобках {} функции

0 голосов
/ 28 января 2019

Внутренняя функция не имеет доступа к переменным родительской функции.Вам необходимо явно передать необходимые родительские переменные во внутреннюю функцию.

В вашем примере вы могли бы избежать внутренней лямбда-функции, изменив свой код на использование '#' и each-both :

q) foo:{#'[floor acos -1;x]}
q) foo 7 8 9
7 7 7
8 8 8
9 9 9

Совет: Всегда сначала пытайтесь реализовать свою логику, используя операторы KDB и наречия.Их можно комбинировать различными способами для создания эффективного и простого кода.

...