Как выполнить несколько операторов в анонимной функции MATLAB? - PullRequest
42 голосов
/ 17 февраля 2009

Я бы хотел сделать что-то вроде этого:

>> foo = @() functionCall1() functionCall2()

Так что когда я сказал:

>> foo()

Это выполнит functionCall1(), а затем выполнит functionCall2(). (Я чувствую, что мне нужно что-то вроде C, оператор )

EDIT:

functionCall1 и functionCall2 не обязательно являются функциями, возвращающими значения.

Ответы [ 6 ]

45 голосов
/ 18 февраля 2009

Попытка сделать все через командную строку без сохранения функций в m-файлах может быть сложной и грязной попыткой, но вот один из способов, которым я придумал ...

Сначала сделайте ваши анонимные функции и поместите их дескрипторы в массив ячеек :

fcn1 = @() ...;
fcn2 = @() ...;
fcn3 = @() ...;
fcnArray = {fcn1 fcn2 fcn3};

... или, если у вас уже определены функции (как в m-файлах), поместите дескрипторы функций в массив ячеек следующим образом:

fcnArray = {@fcn1 @fcn2 @fcn3};

Затем вы можете создать новую анонимную функцию, которая вызывает каждую функцию в массиве, используя встроенные функции cellfun и feval:

foo = @() cellfun(@feval,fcnArray);

Хотя это забавно выглядит, но работает.

РЕДАКТИРОВАТЬ: Если функции в fcnArray необходимо вызывать с входными аргументами, вы должны сначала убедиться, что для ВСЕХ функций в массиве требуется ОДНО одинаковое количество входов. В этом случае в следующем примере показано, как вызывать массив функций с одним входным аргументом каждый:

foo = @(x) cellfun(@feval,fcnArray,x);
inArgs = {1 'a' [1 2 3]};
foo(inArgs);  %# Passes 1 to fcn1, 'a' to fcn2, and [1 2 3] to fcn3


WORD OF WARNING: Документация для cellfun гласит, что порядок , в котором вычисляются выходные элементы, не указан и на него нельзя полагаться. Это означает, что нет никаких гарантий, что fcn1 будет оцениваться до fcn2 или fcn3. Если порядок имеет значение, вышеуказанное решение не следует использовать.

11 голосов
/ 18 февраля 2009

Синтаксис анонимной функции в Matlab (как и в некоторых других языках) допускает только одно выражение. Кроме того, он имеет различную семантику привязки переменных (переменные, которых нет в списке аргументов, имеют значения , лексически связанные во время создания функции, а не привязанные ссылки). Эта простота позволяет Mathworks выполнять некоторые оптимизации за кулисами и избегать многих беспорядочных областей видимости и проблем с временем жизни объектов при использовании их в сценариях.

Если вы определяете эту анонимную функцию внутри функции (не сценария), вы можете создавать именованные внутренние функции. Внутренние функции имеют нормальную лексическую привязку ссылок и допускают произвольное количество операторов.

function F = createfcn(a,...)
  F = @myfunc;
  function b = myfunc(...)
    a = a+1; 
    b = a; 
  end
end

Иногда вы можете избежать неприятностей с советами Гновице.

Будьте осторожны с использованием eval ... он очень неэффективен (он обходит JIT), и оптимизатор Matlab может запутаться между переменными и функциями из внешней области видимости, которые используются внутри выражения eval. Также трудно отлаживать и / или код экстента, который использует eval.

6 голосов
/ 17 октября 2012

Вот метод, который гарантирует порядок выполнения и (с изменениями, упомянутыми в конце) позволяет передавать разные аргументы различным функциям.

call1 = @(a,b) a();
call12 = @(a,b) call1(b,call1(a,b));

Ключ - call1, который вызывает первый аргумент и игнорирует второй. call12 вызывает свой первый аргумент, а затем второй, возвращая значение из второго. Это работает, потому что функция не может быть оценена перед ее аргументами. Чтобы создать свой пример, вы должны написать:

foo = @() call12(functionCall1, functionCall2);

Тестовый код

Вот код теста, который я использовал:

>> print1=@()fprintf('1\n');
>> print2=@()fprintf('2\n');
>> call12(print1,print2)
1
2

Вызов дополнительных функций

Чтобы вызвать 3 функции, вы можете написать

call1(print3, call1(print2, call1(print1,print2)));

4 функции:

call1(print4, call1(print3, call1(print2, call1(print1,print2))));

Для получения дополнительных функций продолжите шаблон вложения.

Передача аргументов

Если вам нужно передать аргументы, вы можете написать версию call1, которая принимает аргументы, а затем внести очевидное изменение в call12.

call1arg1 = @(a,arg_a,b) a(arg_a);
call12arg1 = @(a, arg_a, b, arg_b) call1arg1(b, arg_b, call1arg1(a, arg_a, b))

Вы также можете создавать версии call1, которые принимают несколько аргументов, смешивают и подбирают их соответствующим образом.

1 голос
/ 14 января 2016

Это возможно, используя функцию curly , которая используется для создания списка через запятую.

curly = @(x, varargin) x{varargin{:}};
f=@(x)curly({exp(x),log(x)})
[a,b]=f(2)
1 голос
/ 18 февраля 2009

Если functionCall1() и functionCall2() возвращают что-то и эти данные могут быть объединены, то вы можете сделать это:

>> foo = @() [functionCall1(), functionCall2()]

или

>> foo = @() [functionCall1(); functionCall2()]

Побочным эффектом этого является то, что foo() будет возвращать конкатенацию всех возвращаемых functionCall1() и functionCall2().

Я не знаю, гарантирован ли порядок выполнения functionCall1() и functionCall2().

0 голосов
/ 17 февраля 2009

Может быть, мне не хватает что-то, просто сделайте комбинацию функций CallCall, которая вызывает обе функции для вас.

...