KDB + / Q: Канонический метод представления переменного числа аргументов? - PullRequest
0 голосов
/ 05 августа 2020

Я пытаюсь создать фиктивную функцию в kdb + / q, которая эффективно заменяет заданную функцию той, которая записывает вызовы и т.д. c. т.е.

wrap:{[otherFn;params]
  // update called etc.
  :otherFn[params]
}

// function that replaces target fn
someOtherFn :{show x};

// store reference etc.
// use set to replace function
`.extern.someFn set wrap[someOtherFn];

В этом случае .extern.someFn следует заменить на someOtherFn, и он должен быть вызываемым как таковой:

q) .extern.someFn[1];
      1

количество аргументов функции .ie

q) .extern.someFn[1;3]; // 
      'rank

Сообщает об ошибке ранжирования. Может ли кто-нибудь посоветовать мне, как я могу чего-то добиться в этом отношении? Спасибо.

Ответы [ 2 ]

4 голосов
/ 05 августа 2020

Есть несколько (возможно, веских *) причин делать что-то подобное. Однажды я напишу замену printf в q ?

Самый простой способ заключается в объединении двух трюков с композицией и зачислением.

Первое зачисление - varadi c:

enlist[1;2]
1 2

Композиция затем может использоваться для объединения функций. Я думаю, что наиболее близким к тому, что вы хотите, является:

makeWrapFunc:{[f] (
callerfunc:{[f;params] f . params}f;
'[callerfunc;enlist]
}

Теперь, независимо от ранга обернутой функции, enlist объединит эти параметры в список для вас перед применением.

Я использовал этот трюк в приведенном ниже коде почти с той же целью. В моем случае я хотел выполнить некоторый ввод через существующую функцию и функцию замены и записать результаты для последующего сравнения. https://github.com/darrenarmstrong85/scientist/blob/master/lib/init.q#L97

Есть несколько способов расширить это для частичного применения, проверив количество параметров обернутой функции и привязки с помощью нулей, но я оставлю это как упражнение для читателя: -)

* Возможно, это тоже кошмар отладки. Предостережение разработчику.

1 голос
/ 05 августа 2020

Вы получаете ошибку ранжирования, потому что .extern.someFn, как определено выше, является функцией одной переменной. Если вы хотите применить .extern.someFn к нескольким входам, вы можете использовать итератор:

q).extern.someFn each 1 3;

Изменить: вас может заинтересовать что-то вроде этого:

q)functionWrapper:{[f;args] f . args};
q)testFunction:{x*y};
q)wrappedFunction:functionWrapper[testFunction];
q)wrappedFunction[2 3]
6

Примечание: args должен быть списком. Несколько аргументов не разделяются точкой с запятой. В общем случае смешанных списков аргументы указываются в виде args:(arg1;arg2;...)

...