Re: Procedure to Function
- To: mathgroup at smc.vnet.net
- Subject: [mg8236] Re: Procedure to Function
- From: Robert Villegas <villegas>
- Date: Thu, 21 Aug 1997 21:16:53 -0400
- Sender: owner-wri-mathgroup at wolfram.com
Robert Pratt asked why turning this procedure: > PROCEDURE > > Clear[u, v, x, y, g] > u = x^3 - 3 x y^2 + y; > v[x_, y_] := Integrate[D[u,x],y] + g[x]; > g[x_] := Evaluate[g[x] /.DSolve[D[v[x, y],x] == D[u,y], g[x], x][[1]]]; > v[x, y] > > -x + 3 x^2 y - y^3 + C[1] into this function: > FUNCTION > > Clear[u, v, x, y, g, HarmonicConjugate] > HarmonicConjugate[u_] := > (v[x_, y_] := Integrate[D[u,x],y] + g[x]; > g[x_] := Evaluate[g[x] /.DSolve[D[v[x, y],x] == D[u,y], g[x], > x][[1]]]; > v[x, y]) > HarmonicConjugate[x^3 - 3 x y^2 + y] did not work. Allan Hayes offered a solution that works for this problem: > A general way of avoiding this kind of problem is to prevent the > direct substition. Thus: > > Clear[u, v, x, y, g, HarmonicConjugate] > > HarmonicConjugate[u_] := > (uu=u; > v[x_, y_] := Integrate[D[uu,x],y] + g[x]; > g[x_] := Evaluate[g[x] /.DSolve[D[v[x, y],x] == D[uu,y], g[x], > x][[1]]]; > v[x, y]) This won't work in general, because it relies on uu getting evaluated wherever it is used. It's fine in your example, but other code might contain functions like Plot and FindRoot that hold their arguments, or might use held expressions to construct something. For these cases, which aren't that infrequent, giving uu an initial value and using it instead of u in the code isn't the same as directly substituting the passed value of u into the code. The more general work-around is to have your code disguise function definitions (and any other scoping constructs that use u). Although it's a tad verbose, it's not too bad -- just replace every lhs := rhs with SetDelayed @@ HoldComplete[lhs, rhs] in your code (use Hold instead of HoldComplete if you don't have Mathematica 3.0 yet). In[10]:= Clear[u, v, x, y, g, HarmonicConjugate] HarmonicConjugate[u_] := (SetDelayed @@ HoldComplete[v[x_, y_], Integrate[D[u,x],y] + g[x]]; SetDelayed @@ HoldComplete[g[x_], Evaluate[g[x] /.DSolve[D[v[x, y],x] == D[u,y], g[x], x][[1]]]]; v[x, y]) In[12]:= HarmonicConjugate[x^3 - 3 x y^2 + y] Out[12]= 2 3 x - 3 x y - y + C[1] For debugging these problems, here is an alternative to Trace. Any time you have a function definition f[x_, y_, ...] := stuff you can find out what 'stuff' becomes after the values of x, y, etc. are substituted in, without actually running the code in 'stuff'. Merely wrap HoldForm around the right-hand side: f[x_, y_, ...] := HoldForm[stuff] Then call f with whatever arguments you want, and you can see what really would have gotten evaluated. Example: HarmonicConjugate[u_] := HoldForm[ v[x_, y_] := Integrate[D[u,x],y] + g[x]; g[x_] := Evaluate[ g[x] /. DSolve[D[v[x, y],x] == D[u,y], g[x],x][[1]] ]; v[x, y] ] It reveals a lot: In[99]:= HarmonicConjugate[x^3 - 3 x y^2 + y] Out[99]= 3 2 v[x$_, y$_] := Integrate[D[x + y - 3 x y , x$], y$] + g[x$]; g[x$_] := Evaluate[g[x$] /. 3 2 DSolve[D[v[x$, y], x$] == D[x + y - 3 x y , y], g[x$], x$][[1]] ]; v[x, y] Now it's obvious that the pattern variables of the functions aren't the same as the variables in the expression passed in. Allen's second solution: > Here is another function, though it does not include the arbitrary > constant in the result, > > HarmonicConjugate2[u_,{x_,y_}]:= > (# + Integrate[-D[#,x]-D[u,y],x])&[Integrate[D[u,x],y]] hints at a design flaw in the design of the original function. The original function required that the expression be in terms of variables called 'x' and 'y'. In general, it's bad practice to hard-code the variable names; it's more versatile if function takes the variables as an additional argument, like Integrate or Plot does. That way, a^3 - 3 a b^2 + b will work as well as x^3 - 3 x y^2 + y. You can still have the convenience of assuming 'x' and 'y' if the variables are omitted. HarmonicConjugate3[u_] := HarmonicConjugate3[u, {x, y}] HarmonicConjugate3[u_, {x_, y_}] := Module[{v, g}, v[x_, y_] := Integrate[D[u, x], y] + g[x]; g[x_] = g[x] /. DSolve[D[v[x, y], x] == D[u, y], g[x], x][[1]]; v[x, y] ] Making v and g local variables instead of global is useful because if you keep making corrections to this code, you won't have a pile-up of mistaken definitions to v and g. And you're guaranteed they won't interfere with other v and g. In[6]:= HarmonicConjugate3[x^3 - 3 x y^2 + y] Out[6]= 2 3 x - 3 x y - y + C[1] In[7]:= HarmonicConjugate3[x^3 - 3 x y^2 + y, {x, y}] Out[7]= 2 3 x - 3 x y - y + C[1] In[8]:= HarmonicConjugate3[a^3 - 3 a b^2 + b, {a, b}] Out[8]= 2 3 a - 3 a b - b + C[1] Robby Villegas