Why Can an Anonymous Function be Defined with a Non-Existent Parameter?

7 ビュー (過去 30 日間)
Paul
Paul 2025 年 7 月 6 日
編集済み: Paul 2025 年 7 月 8 日
Define an anonymous function with one argument (x) and one parameter (y)
f = @(x) x + y;
I'm suprised that line sails through without an error (or even a warning) even though there is no variable called y in the workspace at the time f() is defined.
Calling f results in an error (unsurprisingly)
try
f(2)
catch ME
ME.message
end
ans = 'Unrecognized function or variable 'y'.'
Once f() is defined, I don't believe there is any way to subsequently define y such that f() works.
Would it be better if an error (or at least a warning) is generated at the time of function definition rather than at the time of function execution?

採用された回答

Steven Lord
Steven Lord 2025 年 7 月 6 日
Once f() is defined, I don't believe there is any way to subsequently define y such that f() works.
Sure there is. Let's first reproduce the failure:
which -all y % It doesn't exist
'y' not found.
f = @(x) x+y;
try
f(1) % This will error
catch ME
fprintf("Error: %s\n", ME.message)
end
Error: Unrecognized function or variable 'y'.
So it does in fact throw an error. Now let's make it work. Note that the only reference to f below is when I call it; I haven't changed the definition of f at all.
cd(tempdir)
fid = fopen('y.m', 'wt');
fprintf(fid, "function z = y\nz = pi;\n");
fclose(fid);
Is y now defined?
which -all y
/tmp/y.m
What is it?
dbtype y.m
1 function z = y 2 z = pi;
Can we call f?
result = f(1) % pi + 1
result = 4.1416
Does it have the value we expect it should if it called the y.m function I created above?
result == (pi + 1) % true
ans = logical
1
Instead of writing y.m, I could have added a folder with a y function to the MATLAB search path or cd to such a folder.
  7 件のコメント
Steven Lord
Steven Lord 2025 年 7 月 7 日
Is it reasonable to ask what c, d, and e could be at execution time that allows f to execute w/o error?
Sure.
We know that neither c, d, nor e can be variables in the caller's workspace (in particular, neither c nor d can be function_handles in the caller's workspace, which is a lesson I learned the hard way).
Because of the clearvars call.
c and d can be m-functions on the search path, as @Steven Lord discussed above.
Correct. They can even be functions that weren't on the path when the anonymous function was created, but are on the path when it is executed.
If f is executed in a script or m-function, can c and d be local functions in the file which f is executing?
Yes. Function handles (and anonymous functions are function handles) "remember" the scope in which they were created. See this documentation page, specifically the last part of the "Creating Function Handles" section. That's why a function can return a function handle to one of its local functions and have that be callable from outside. The local function was in scope when the function handle was created, so it's callable through the function handle.
fh = makeFunctionHandle();
canCallViaFunctionHandle = fh(1:3)
canCallViaFunctionHandle = 1×3
2 4 6
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
try % So I can call stuff later in this comment
cannotCallDirectly = localFunction(1:3) % Not in scope
catch ME
fprintf("Direct call threw error:\n\t%s\n", ME.message)
end
Direct call threw error: Undefined function 'localFunction' for input arguments of type 'double'.
function fh = makeFunctionHandle()
fh = @localFunction;
function y = localFunction(x)
y = x*2;
end
end
Can c or d be private or nested (I've never used these before, so don't know if the question even makes sense)?
Nested: yes. See above. localFunction is nested inside makeFunctionHandle.
Private: I believe so, as long as the function handle was created in a function in the parent folder of the private folder. I have not tried this, though.
I suppose d could be method of the class of a?
Sure. And which class's d method gets called is determined at run-time. For example, if you replaced d(a) with plot(a), well, there are a lot of classes that have a method named plot. [And I'm sure this is not a complete list; user-defined classes, classes in products that aren't supported in the MATLAB instance used by MATLAB Answers to evaluate code, classes that haven't been loaded into memory yet, ...] Thought for this particular example it would need to be a class with both plot and plus methods (due to "a + <stuff>"), which may narrow things down a little.
w = which('plot', '-all')
w = 48×1 cell array
{'built-in (/MATLAB/toolbox/matlab/graphics/graphics/graph2d/plot)'} {'/MATLAB/toolbox/matlab/bigdata/@tall/plot.m' } {'/MATLAB/toolbox/matlab/graphics/math/@polyshape/plot.m' } {'/MATLAB/toolbox/matlab/graphics/math/@digraph/plot.m' } {'/MATLAB/toolbox/matlab/graphics/math/@alphaShape/plot.m' } {'/MATLAB/toolbox/matlab/graphics/math/@graph/plot.m' } {'/MATLAB/toolbox/matlab/timeseries/@timeseries/plot.m' } {'/MATLAB/toolbox/bioinfo/bioinfo/@phytree/plot.m' } {'/MATLAB/toolbox/bioinfo/bioinfo/microarray/@HeatMap/plot.m' } {'/MATLAB/toolbox/bioinfo/bioinfo/microarray/@clustergram/plot.m' } {'/MATLAB/toolbox/curvefit/curvefit/@sfit/plot.m' } {'/MATLAB/toolbox/curvefit/curvefit/@cfit/plot.m' } {'/MATLAB/toolbox/econ/econ/@semiconjugateblm/plot.m' } {'/MATLAB/toolbox/econ/econ/@conjugateblm/plot.m' } {'/MATLAB/toolbox/econ/econ/@customblm/plot.m' } {'/MATLAB/toolbox/econ/econ/@mixsemiconjugateblm/plot.m' } {'/MATLAB/toolbox/econ/econ/@blm/plot.m' } {'/MATLAB/toolbox/econ/econ/@empiricalblm/plot.m' } {'/MATLAB/toolbox/econ/econ/@mixconjugateblm/plot.m' } {'/MATLAB/toolbox/econ/econ/@diffuseblm/plot.m' } {'/MATLAB/toolbox/econ/econ/@lassoblm/plot.m' } {'/MATLAB/toolbox/ident/ident/@iddata/plot.m' } {'/MATLAB/toolbox/ident/nlident/@idnlhw/plot.m' } {'/MATLAB/toolbox/ident/nlident/@idnlarx/plot.m' } {'/MATLAB/toolbox/mbc/mbcdata/@cgrules/plot.m' } {'/MATLAB/toolbox/mbc/mbcmodels/@localmulti/plot.m' } {'/MATLAB/toolbox/mbc/mbcmodels/@xregtransient/plot.m' } {'/MATLAB/toolbox/mbc/mbcmodels/@localavfit/plot.m' } {'/MATLAB/toolbox/mbc/mbcmodels/@xregmodel/plot.m' } {'/MATLAB/toolbox/mbc/mbcmodels/@xregtwostage/plot.m' }
numberOfPlotMethods = numel(w)
numberOfPlotMethods = 48
e can't be a struct in the caller's workspace. But I suppose it could be a function (m-function, or ?) that returns a struct that has a field g? Any other possibilities for e?
Yes, it could be a function that returns a struct into which you directly index. It could also be the name of a namespace with a function named g that can be called with 0 input arguments and 1 output argument. Or it could be the name of a class with a Static method named g that can be called with 0 input arguments and 1 output argument. I'm guessing there's probably something I'm forgetting but I suspect those three are the most likely cases you're going to encounter.
Paul
Paul 2025 年 7 月 7 日
編集済み: Paul 2025 年 7 月 8 日
I read the "Creating Function Handles" section and I don't understand how it applies in this discussion. The only function handle in this discussion is f, so I don't understand how that section can answer a question about c, d and e. Are c and d and (possibly) e also function handles?
Also, if e is a function with no input arguments and returns a struct with a field named g, then it still has to be called with parentheses
f = @(a) a + c + d(a) + e().g;
Do you think the doc page Anonymous Functions should be updated? It has a section on "Variables in the Expression," but if c and d and e are not defined at the time f is defined then they are not variables and that section wouldn't apply. Also, this section might want to show an example with variable that's a function handle. Seems like there should be an additional section on "Functions in the Expression" that basically says that function calls (not through function handles) are resolved at execution time using the normal precedence rules (assuming that's the case).

サインインしてコメントする。

その他の回答 (0 件)

カテゴリ

Help Center および File ExchangeMatrix Indexing についてさらに検索

製品


リリース

R2025a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by