Anonymous functions behavior is weird
Ältere Kommentare anzeigen
I encountered a weird behavior with anonymous functions
take a look at this class:
classdef object1 < handle
properties
x;
end
methods
function this = foo(this, x)
this.x = x;
this.print();
end
function this = foo1(this, x)
this.x = x;
end
function this = foo2(this, x, y)
if x > y
this.x = x;
else
this.x = y;
end
end
function this = print(this)
disp(['printing ' num2str(this.x)]);
end
end
end
Now because all the functions return this, I can use it to chain commands:
object1().foo(10).foo1(20).foo2(10, 20).foo(1:10)
printing 10
printing 1 2 3 4 5 6 7 8 9 10
ans =
object1 with properties:
x: [1 2 3 4 5 6 7 8 9 10]
Ok, this is nice, now I want to send this little functionality as a callback function to some operation
so let's throw this in an anonymous function:
@() object1().foo(10).foo1(20).foo2(10, 20).foo(1:10)
ans =
function_handle with value:
@()%T0.1%1%.foo(10).foo1(20).foo2(10,20).foo(1:10)
So far, so good...
now when I try to pu it in a variable it getss weird:
func = @() object1().foo(10).foo1(20).foo2(10, 20).foo(1:10)
Error: This statement is incomplete.
and weird gets even weirder:
@() object1().foo(10).foo1(20).foo2(10, 20).foo(1:10);
func = ans
func =
function_handle with value:
@()%T0.1%1%.foo(10).foo1(20).foo2(10,20).foo(1:10)
func();
printing 10
printing 1 2 3 4 5 6 7 8 9 10
Expected one output from a curly brace or dot indexing expression, but there were 0 results.
Error in @()%T0.1%1%.foo(10).foo1(20).foo2(10,20).foo(1:10)
This is strange as I saw already that this line of code returns a value
This behavior persists if i send it as an argument to a function instead of saving in a varialbe
that much at least is expected...
I know I can work around that by using function notation instead of dot indexing
but I like to avoid the pyramid of doom when I can, as this code is by far less readable:
func = @() foo(foo2(foo1(foo(object1(), 10), 20), 10, 20), 1:10)
func =
function_handle with value:
@()foo(foo2(foo1(foo(object1(),10),20),10,20),1:10)
>> func()
printing 10
printing 1 2 3 4 5 6 7 8 9 10
ans =
object1 with properties:
x: [1 2 3 4 5 6 7 8 9 10]
Sugestions?
4 Kommentare
Joseph Transom
am 7 Aug. 2019
Bearbeitet: Joseph Transom
am 7 Aug. 2019
Chaining-fail is understandable because ML doesn't do it. What's pretty annoying is that ML's anonymous function stuff has stupid issues in scripts.
Something simple: ML's timetable functionality is poor, so you have to do a bunch of things by varfun(). (alternatively, you have to save the VariableNames and RowTimes, table2array the timetable, do your stuff, then re-timetable it.
Consider the following, with rData a timetable (78 × 18).
To divide every column by 100 you have to do
f_100 = @(x) x/100;
rData = varfun(f_100, rData); % works every time the script is run
means = varfun(@mean, rData); % works every time, too - small mercies
However let's say you want the std(rData)*sqrt(12) - you're annualising a monthly std().
So. Since this is a column operation on a timetable, you know in advance that ML can't do it, so you know you have to varfun - easy enough.
f_sd = @(x) std(x)*sqrt(12); % Not rocket surgery: what could go wrong?
sds = varfun(@f_sd, rData); % works - ONCE.
If you run that script again (say, after adding some code to collate the outputs), you get this ->
"f_sd" was previously used as a variable, conflicting with its use here as the name of a function or command.
f_sd appears nowhere except the two lines above.
There is a clear all; at the top of the script.
So ML is ballsing it up somewhere.
Lest readers imagine that I haven't wasted even more time trying to get ML to do what it ought to, I also tried
sds = varfun(@std, rData).*sqrt(12); % and just *12
No joy:
Undefined operator '.*' for input arguments of type 'timetable'.
Of course it didn't work - anyone who would expect otherwise clearly deserves some sniffy supercilious dismissal of their dismay.
In R or Python (pandas) or any SQL scripting language, performing column-wise calculations on a time- or date-indexed dataframe is a trivial undertaking.
Likewise, in those other platforms, functions behave as they ought to, and RStudio and [GUI of choice for Python] don't eventually cling to 4GB of RAM if left open for 24 hours with an environment that contains a 100-line script and a single 7MB data object.
Maybe I'm just expecting too much of modern subscription software; conversely, maybe ML is Kodak in an age of ubiquitous digital cameras.
I haven't been this disappointed in a piece of 'brand' software since I was forced to use MapInfo in preference to QGIS.
Fortunately (for me) I'm just tidying up some ML code before porting it to R. And work's paying for the license.
Rik
am 7 Aug. 2019
My personal experience is that the newer data structures need several years to mature. If there happens to be a function that does what you need, it works like a charm. Otherwise you're often better off converting to another data type (which is generally the point I choose not to convert back to the newer data type).
Some (most?) of the things you describe sound like bugs. Have you tried reaching out to support? On the few occasions I sent them feedback they were quick with a response.
Also, I have never had your experience with such extreme ram usage, except maybe using Chrome. I'm curious what kind of script/function would cause that.
Guillaume
am 7 Aug. 2019
Your rant would carry more weight if you'd used valid examples.
f_sd = @(x) std(x)*sqrt(12);
sds = varfun(@f_sd, rData); % works - ONCE.
doesn't even work once, since the correct syntax for passing anonymous functions (which are already function handles) is:
sds = varfun(f_sd, rData); % NO @
And I don't get any issue making it work more than once:
>> rData = timetable(datetime + hours(1:100)', rand(100, 1), randi(50, 100, 1));
>> f_sd = @(x) std(x)*sqrt(12)
f_sd =
function_handle with value:
@(x)std(x)*sqrt(12)
>> sds = varfun(f_sd, rData)
sds =
1×2 timetable
Time Fun_Var1 Fun_Var2
____________________ _________________ ________________
08-Aug-2019 00:11:10 0.926696527765659 52.4154037040119
>> sds = varfun(f_sd, rData)
sds =
1×2 timetable
Time Fun_Var1 Fun_Var2
____________________ _________________ ________________
08-Aug-2019 00:11:10 0.926696527765659 52.4154037040119
As for,
sds = varfun(@std, rData).*sqrt(12);
Well, yes varfun returns a timetable unless you specify 'OutputFormat', 'Uniform', and multiplying a timetable by anything is undefined. What would you expect the result of the multiplication of 12 by a timetable containing a numeric variable, a text variable and a variable containing a objects?
Akzeptierte Antwort
Weitere Antworten (0)
Kategorien
Mehr zu Common Operations finden Sie in Hilfe-Center und File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!