web-dev-qa-db-ja.com

MATLAB無名関数で複数のステートメントを実行する方法は?

私はこのようなことをしたいです:

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

だから私が言ったとき:

_>> foo()
_

functionCall1()を実行してから、functionCall2()を実行します。 ( C、演算子 のようなものが必要だと思います)

編集:

_functionCall1_および_functionCall2_は、必ずしも値を返す関数ではありません。

43

関数をmファイルに保存せずにコマンドラインからすべてを実行しようとすると、複雑で面倒な作業になる可能性がありますが、これが私が思いついた1つの方法です...

まず、 無名関数 を作成し、それらの ハンドルセル配列 に配置します。

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

...または、関数がすでに定義されている場合(mファイルなど)、関数ハンドルを次のようにセル配列に配置します。

fcnArray = {@fcn1 @fcn2 @fcn3};

次に、組み込み関数 cellfun および feval を使用して、配列内の各関数を呼び出す新しい無名関数を作成できます。

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

見た目はおかしいですが、機能します。

EDIT:fcnArrayの関数を入力引数で呼び出す必要がある場合は、最初にすべての関数を確認する必要があります配列内には同じ数の入力が必要です。その場合、次の例は、それぞれ1つの入力引数を持つ関数の配列を呼び出す方法を示しています。

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 のドキュメントには、出力要素が計算される順序は指定されていないため、信頼しないでください。これは、fcn1fcn2またはfcn3の前に評価されるという保証がないことを意味します。順序が重要な場合は、上記のソリューションを使用しないでください。

45
gnovice

Matlabの無名関数構文(他のいくつかの言語と同様)では、1つの式しか使用できません。さらに、さまざまな変数バインディングセマンティクスがあります(引数リストにない変数は、参照がバインドされるのではなく、関数の作成時にが字句的にバインドされます) )。この単純さにより、Mathworksはバックグラウンドでいくつかの最適化を実行し、スクリプトで使用する際の厄介なスコープやオブジェクトの有効期間の問題を回避できます。

この無名関数を(スクリプトではなく)関数内で定義している場合は、名前付き内部関数を作成できます。内部関数には通常の字句参照バインディングがあり、任意の数のステートメントを許可します。

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

時々あなたはgnoviceの提案のようなトリックで逃げることができます。

Evalの使用には注意してください...これは非常に非効率的であり(JITをバイパスします)、Matlabのオプティマイザーはeval式内で使用される外部スコープの変数と関数の間で混乱する可能性があります。また、evalを使用するコードをデバッグしたり拡張したりすることも困難です。

13
Mr Fooz

これは、実行順序を保証し、(最後に記載されている変更を加えて)さまざまな引数をさまざまな関数に渡すことを可能にするメソッドです。

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

キーはcall1で、最初の引数を呼び出し、2番目の引数を無視します。 call12は、最初の引数を呼び出してから2番目の引数を呼び出し、2番目の引数から値を返します。関数は引数の前に評価できないため、機能します。例を作成するには、次のように記述します。

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を作成することもできます。

6
Eponymous

カンマ区切りのリストを作成するために使用される curly 関数を使用して可能です。

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

functionCall1()functionCall2()が何かを返し、それらの何かを連結できる場合は、次のようにすることができます。

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

または

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

これの副作用は、foo()functionCall1()functionCall2()が返すものの連結を返すことです。

functionCall1()functionCall2()の実行順序が保証されているかどうかはわかりません。

1
ManWithSleeve

何かが足りないかもしれません。両方の関数を呼び出す関数の組み合わせ呼び出しを行ってください。

0
MatlabDoug