2

無名関数を格納するファイル funcs.m があります。それらは、それがあるディレクトリ内のファイルで使用できる必要があります。現在、匿名関数を使用してfuncs.m別のファイルでファイルを実行していますが、これは間違ったやり方だと思います。main.m やそのネストされた関数 nest.m などの他の関数は、funcs.m の無名関数を使用する必要があります。ファイルが同じフォルダーにあるため、パスではこの問題は解決しないと思います。基本的に、匿名関数をすべてのファイルにコピーして貼り付けることで、この問題を解決できますが、コードの匂いがします。

Matlab で anon 関数を持つ funcs.m を再利用する方法はありますか?

main.m

function main
funcs; % loads the anonymous functions
nest(par1,...,parN)
end

巣.m

function nest(par1,...,parN)
funcs; %ERRR: This fires err, why? Look: this was sourced already in main.m!
function neededOnlyHere(par100)
    bq(q,A) %This needs the functions of the funcs
end

neededOnlyHere(somePar) %ERR to use the anon funcs from funcs
end

関数 main.m および nest.m は、匿名関数を持つこの関数 funcs.m を使用します

bq=@(q,A) q*A;                              %Bolded q
I=@(ii,jj,A) find(A(ii,:)==1 & A(jj,:)==0); 
AiNotj=zeros(1,Ncut);                       
...

エラー

Attempt to add "bq" to a static workspace.
 See MATLAB Programming, Restrictions on
 Assigning to Variables for details.

Error in funcs (line 10)
bq=@(q,A) q*A;
%Bolded q
4

2 に答える 2

6

壊れる理由

nest.mネストされた関数を持つと、それを囲む関数のワークスペースが「静的ワークスペース」になるため、呼び出し時にエラーが発生します。つまりeval()、 、assignin()、またはその他の「動的」手法を使用して変数名を追加することはできません。その関数のテキストで明示的に割り当てられた変数のみが許可されます。スクリプトを評価してローカル変数を定義すること (呼び出し時に行っていることfuncs.m) は「動的」であるため、ネストされた関数を含む関数では禁止されています。main にはmain.mネストされた関数がなく、したがって「動的な」ワークスペースであるため、機能します。

静的ワークスペースとネストされた関数で動作するように変更するには、いくつかの方法があります。最初に質問することは、それらを本当に無名関数にする必要があるかどうかです。

代わりにパッケージ関数を使用する

それらを匿名関数自体にする必要がない場合は、それらを分割して、それぞれを通常の関数として独自の.mファイルに入れます。例: bg.mI.mAiNotj.mなど。その後、それらはすべて、そのディレクトリ内の他のすべての機能で利用できます。

それがファイルの混乱になる場合、またはそれらをスコープして、本当に必要な選択された関数 (つまり、現在 を呼び出している関数funcs()) だけが利用できるようにしたい場合は、それらをパッケージに貼り付けることができます。というサブディレクトリを作成し+myfuncs、小さな関数ファイルをすべてそこに移動します。例: +myfuncs/bq.m, . (プレフィックスは、ディレクトリがパッケージであることを Matlab に伝えます。) 次に、現在呼び出している場所の直接の代わりとして実行することで、それらすべてを関数スコープに取り込むことができます。+myfuncs/I.m+myfuncs/AiNotj.m+import myfuncs.*funcs()

function nest(par1,...,parN)
import myfuncs.*;
function neededOnlyHere(par100)
    bq(q,A) % This will work, resolving to myfuncs.bq
end

import myfuncs.*コマンドラインから を実行して、インタラクティブに利用できるようにすることもできます。

これはおそらく、Matlab 自体がこのような関連する関数のクラスターを整理する方法であり、私の最初のアプローチです。それは最も「臭い」私見です。便宜上、単一のファイルでそれらすべてを編集できるようにしたい場合はfuncs.m、Perl または funcs.m を解析するもので小さなコードマンガーを記述し、それらすべてを前処理ステップとして同等の個々の関数として出力できます。(このように M ファイルで複数のトップレベル関数を定義できないのは少し残念だと思いますが、まあまあです。)

本当に匿名関数を使用する必要がある場合は、いくつかの回避策があります。

構造体で関数を渡す

funcs() 関数を変更して、ローカル変数名の代わりにフィールド名を使用して、これらすべての無名関数の構造体を実際に返すことができます。

function out = funcs
out.bq=@(q,A) q*A;                              %Bolded q
out.I=@(ii,jj,A) find(A(ii,:)==1 & A(jj,:)==0); 
out.AiNotj=zeros(1,Ncut);                       

このためには、すべての関数参照の前に、それらを保持している構造体名を付ける必要があります。これがどれほど大きな取引であるかはわかりません。

function nest(par1,...,parN)
fs = funcs;
function neededOnlyHere(par100)
    fs.bq(q,A) %This needs the functions of the funcs
end

変数の事前割り当て

funcs() をそのまま動作させるには、使用するすべての関数名で変数を静的に事前に割り当てることができるため、Matlab パーサーはそれらを静的に割り当てられた変数として認識します。次に funcs() を呼び出すと、既存の変数の値が再割り当てされます。これは動的ワークスペースで許可されています。

function nest(par1,...,parN)
[bq, I, AiNotj] = deal();  % Preallocate all names from funcs
funcs;
function neededOnlyHere(par100)
    bq(q,A) %This needs the functions of the funcs
end

新しい関数名が追加されるたびに funcs を使用するすべてのファイルを再編集する必要があるため、これは少し面倒です。funcs.m少なくとも、"[bg, I, AiNotj,...] = deal();" を解析して出力することで、そのコード行を自動生成する小さな perl スクリプトを作成できます。見つかったすべての関数を使用して、それをコードにコピーするだけです。

これを行う別の方法は、funcs が実際にすべての関数を出力リストに返すようにすることです。funcs.mこれには、既存の無名関数の順序を削除または変更しない限り、新しい関数を に追加しても機能し続けるという利点があります。

function [bg,I,AiNotj] = funcs()
bg = ...
I = ...

% And then in the calling functions:
[bg,I,AiNotj] = funcs(); % which you can copy and paste from funcs.m's header
于 2013-06-08T03:13:43.163 に答える