Как выполнить несколько операторов в анонимной функции MATLAB?

41

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

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

Итак, когда я сказал:

>> foo()

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

EDIT:

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

  • 0
    Должны ли functionCall1 и functionCall2 когда-либо принимать входные значения? Если нет, то решение, которое я дал ниже, должно работать. Если они принимают значения, моё решение все еще может работать, но нуждается в некоторой модификации.
  • 0
    Я обновил свой ответ с примером для передачи входных аргументов, на всякий случай, если вам это нужно.
Теги:
command-line
anonymous-function

6 ответов

45
Лучший ответ

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

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

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

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

fcnArray = {@fcn1 @fcn2 @fcn3};

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

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

Несмотря на забавный вид, он работает.

EDIT: Если функции в 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


СЛОВО ПРЕДУПРЕЖДЕНИЯ: В документации для cellfun указано, что порядок, в котором вычисляются выходные элементы, не указан и на него нельзя положиться. Это означает, что нет гарантий, что fcn1 оценивается до fcn2 или fcn3. Если порядок имеет значение, вышеуказанное решение не должно использоваться.

  • 0
    милая! Я пытался выяснить что-то подобное.
  • 1
    Интересно! И, конечно, вы можете просто объявить fcnArray напрямую, а не как отдельную переменную, например что-то вроде: myfun = @() cellfun(@feval,{@() xlim([1 5]), @() xlabel('seconds')}); Теперь вызов myfun установит на рисунке и xlim, и xlabel.
11

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

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

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

Иногда вы можете уйти с трюками, такими как предложение gnovice.

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

6

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

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

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

curly = @(x, varargin) x{varargin{:}};
f=@(x)curly({exp(x),log(x)})
[a,b]=f(2)
1

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

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

или

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

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

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

  • 0
    Да, к сожалению, я имею дело с функциями, которые не возвращают значения.
0

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

  • 0
    ну, я надеюсь, что смогу сделать все это из командного окна ... это будет возможно?
  • 0
    Возможно, вы могли бы, но зачем? Используйте скрипт и файл функций. Это облегчает итерацию вашей работы, просто запустив скрипт драйвера.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню