Can you perform a delayed set (:= in Mathematica)

2020-02-14 04:07发布

问题:

So, I've recently converted from Mathematica to Matlab, and while Matlab has most of Mathematica's useful features, I can't figure out how to perform the equivalent of Mathematica's delayed set operation ':=' which assigns a variable a value in a lazy fashion.

For example, in Mathematica:

y = 2;

x := y;

y = 3;

x

would give the value of x as 3, whereas the only way I can get this same behavior in Matlab is:

y = 2;

x = @()(y);

y = 3;

x()

which, while technically answering my question, is a pretty ad hoc work around and requires treating x as a function.

So is there a more natural way to do this is Matlab?

EDIT:

my ad-hoc solution only works when y is a field of a handle class, I left this out of the code for clarity (it should be someclass.y). Preferably the answer to my question wouldn't have this restriction, but I'd still accept it if it did.

回答1:

Lazy evaluation is primarily used in functional programming languages and MATLAB is procedural/OOP based. As such, an equivalent of SetDelayed does not exist. If you try to use anonymous functions as you've demonstrated, it will not work, as Amro has already pointed out.

However, if you have access to the symbolic computing toolbox, you can get by with something that could be considered an equivalent of := (a flimsy equivalence, if you ask me). Here's an example:

syms x y z; %#Declare x, y and z as symbolic variables
x=y+2; %#Define some value for x
f=@(x)x.^2; %#Define an anonymous function. 

f(x)

ans =

(y + 2)^2

%#Check with z
f(z)

ans =

z^2   

You can see that it uses the actual definition of f, and does not capture the definition of x as it did in your numerical example. You can also change the definition of x to say, x=1/y and f(x) will now use the present definition of x. Note that f is merely a function handle and will take numerical/symbolic arguments. E.g.,

f(1:5)

ans =

     1     4     9    16    25

The part where it does not resemble := is that it applies the definitions only for the terms present in the expression and does not go deeper (i.e., it does not evaluate the definitions for the different set of variables that might arise as a result of the first evaluation). This is hardly a surprise as MATLAB is not a rule based language. To illustrate my point:

y=z^3; %#Define y
f(x)

ans = 
(y + 2)^2 %#The definition for y is not used.

whereas Mathematica would've given you (z^3+2)^2.

Clear[y, z, x, f]
f[x_] := x^2;
y := z^3; x := y + 2;

f[x]

Out[1]= (2 + z^3)^2

It is best if you embraced the differences in the two languages and tried to stick with what is idiomatic in each. Trying to deny it and program in one like the other could make your life miserable (e.g., starting with a C background and adamantly writing For loops in Mathematica).



回答2:

Actually your proposed solution doesn't work as expected:

y = 2;
x = @()(y);
y = 3;
x()

when you define the anonymous function, it create a closure and captures/copies the value of y at that moment (now it has its own copy of y). Then if you change the y on the outside, it would not affect the one created in the closure, thus in your example the last value would return 2 not 3

The only way I can think of is to encapsulate the variable in a closure and expose set/get methods (just like in OOP)

IMO, MATLAB and Mathematica have two very different languages, thus I would embrace the MATLAB-way and not try emulate features of other languages (that is usually not the best thing to do)