简体   繁体   中英

How to execute multiple statements in a MATLAB anonymous function?

I'd like to do something like this:

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

So that when I said:

>> foo()

It would execute functionCall1() and then execute functionCall2() . (I feel that I need something like the C , operator )

EDIT:

functionCall1 and functionCall2 are not necessarily functions that return values.

Trying to do everything via the command line without saving functions in m-files may be a complicated and messy endeavor, but here's one way I came up with...

First, make your anonymous functions and put their handles in a cell array :

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

...or, if you have functions already defined (like in m-files), place the function handles in a cell array like so:

fcnArray = {@fcn1 @fcn2 @fcn3};

Then you can make a new anonymous function that calls each function in the array using the built-in functions cellfun and feval :

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

Although funny-looking, it works.

EDIT: If the functions in fcnArray need to be called with input arguments, you would first have to make sure that ALL of the functions in the array require THE SAME number of inputs. In that case, the following example shows how to call the array of functions with one input argument each:

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: The documentation for cellfun states that the order in which the output elements are computed is not specified and should not be relied upon. This means that there are no guarantees that fcn1 gets evaluated before fcn2 or fcn3 . If order matters, the above solution shouldn't be used.

The anonymous function syntax in Matlab (like some other languages) only allows a single expression. Furthermore, it has different variable binding semantics (variables which are not in the argument list have their values lexically bound at function creation time, instead of references being bound). This simplicity allows Mathworks to do some optimizations behind the scenes and avoid a lot of messy scoping and object lifetime issues when using them in scripts.

If you are defining this anonymous function within a function (not a script), you can create named inner functions. Inner functions have normal lexical reference binding and allow arbitrary numbers of statements.

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

Sometimes you can get away with tricks like gnovice's suggestion.

Be careful about using eval... it's very inefficient (it bypasses the JIT), and Matlab's optimizer can get confused between variables and functions from the outer scope that are used inside the eval expression. It's also hard to debug and/or extent code that uses eval.

Here is a method that will guarantee execution order and, (with modifications mentioned at the end) allows passing different arguments to different functions.

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

The key is call1 which calls its first argument and ignores its second. call12 calls its first argument and then its second, returning the value from the second. It works because a function cannot be evaluated before its arguments. To create your example, you would write:

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

Test Code

Here is the test code I used:

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

Calling more functions

To call 3 functions, you could write

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

4 functions:

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

For more functions, continue the nesting pattern.

Passing Arguments

If you need to pass arguments, you can write a version of call1 that takes arguments and then make the obvious modification to 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))

You can also make versions of call1 that take multiple arguments and mix and match them as appropriate.

It is possible, using the curly function which is used to create a comma separated list.

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

If functionCall1() and functionCall2() return something and those somethings can be concatenated, then you can do this:

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

or

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

A side effect of this is that foo() will return the concatenation of whatever functionCall1() and functionCall2() return.

I don't know if the execution order of functionCall1() and functionCall2() is guaranteed.

也许我想不通,只需创建一个函数combinCall即可为您调用这两个函数。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM