1
$\begingroup$

What I want is an f that will work like this:

x = 1;
myOut = f[x];    (* it should return {x -> 2} , the 2 is the new data *)
x /.myOut        (* execute this line if I want to overwrite the current x;
                    or I can leave my old x as is but still have the new data
                    in myOut  *) 

The main challenge for me now is to:

print the rule to a variable, while this variable is already assigned a value, say, x = 1.

In the module I have to avoid using its name x because it will automatically get substituted by 1 (in this example above). The variable name should be provided by the user so that its name is unknown and I cannot hard-code it in my module.

So far, I can fetch the input variable name x no problem. I can also overwrite x inside the module without explicitly using its name. I'm stuck at printing it in a rule.

Using HoldForm[ ] creates a tiny white space that ruins the rule (while avoiding being detected as not a rule when executed!), and neither does Defer[ ] work in a mysterious way (to me).

Below is this failed attempt with the tiny white space:

myFunc[inVar_] := Module[{newData,},

   newData = 1 + inVar; (* just some computation *)

   Print[ HoldForm[ inVar ] -> newData ];
    (* Besides Print[ ], I also tried Return[], List[], or just the rule (expression) itself; the outcome are all the same *)

   ];  (* End of Module *)

For example, myOut = myFunc[x] will print x->2 with a tiny white space right after the x and before the arrow. It kind of looks like x,->2 where the comma represents the white space.

The usual x/.myOut will not work because of this. I've tried it, if I manually remove that tiny space then the rule will work.

Besides HoldForm[ ], using a string for the variable name creates double quotes. Inactive[ ], Unevaluated[ ], With[ ] don't work either, at least the ways I've tried.

I'm currently working on MakeExpressions[ ] and boxes, but I haven't made much progress and am wondering if I'm on the right track.

Thank you very much.

-------- a little info hopefully for more efficient discussions ----

Thanks to the many answers to other questions provided by Kuba, Mr.Wizard and Leonid, just to name a few, I have learned how to:

(a) obtain the variable name provided by the user and append sequential index or strings etc to make use of it,

(b) inject stuff into held expressions, one of the coolest thing I've ever seen with /._[x__] ->

(c) forcefully assign values to existing variables without explicitly using its name, like so.

As a whole I consider myself a beginner, knowing basic syntax and some isolated tricks only.

$\endgroup$
6
  • $\begingroup$ can you give an example what kind of output you are expecting from what kind of input. $\endgroup$
    – Sumit
    May 9, 2016 at 16:07
  • $\begingroup$ myOut = myModule[ var, blah ], either this or without the assignment to myOut, I'd like the output to be % = {var -> some nested list } such that I can choose to update or not with this: var /. % $\endgroup$ May 9, 2016 at 16:28
  • $\begingroup$ The point is that the rule ties the variable name with the output, instead of the data being just some lists themselves and not obvious which list goes to which variable. At the same time, printing the variable names with strings causes extra work in accessing the outcome. $\endgroup$ May 9, 2016 at 16:34
  • $\begingroup$ how about x/.x->f[x]. You don't need any module for that. $\endgroup$
    – Sumit
    May 11, 2016 at 7:45
  • 1
    $\begingroup$ f[x0_] := HoldPattern[x] -> 2? You can't simply have x -> 2 if x has been assigned a value (e.g., x = 1). Or possibly ClearAll[f]; SetAttributes[f, HoldAll]; f[var_] := Module[{newData}, <code to calculate newData >; HoldPattern[var] -> newData]. $\endgroup$
    – Michael E2
    Jul 14, 2016 at 4:31

2 Answers 2

1
$\begingroup$

It's hard to achieve exactly the same thing you want, because ReplaceAll and Rule don't have Hold* attributes i.e. both of them automatically evaluate their arguments. Just observe the output of the following code piece:

x = 1;
x + 1 /. x -> 2 // Trace
(* {{{x, 1}, 1 + 1, 2}, 
   {{x, 1}, 1 -> 2, 1 -> 2}, 
   2 /. 1 -> 2, 2} *)

Before ReplaceAll begins to work, x + 1 will evaluate first and become 2, then x in the left hand side of Rule will evaluate to 1, finally x + 1 /. x -> 2 actually becomes 2 /. 1 -> 2, which certainly won't output 3 because pattern matching is syntactic matching rather than semantic matching. (If you feel confused, read this. )

However, something very similar can be achieved, we just need to introduce a help function and adjust the evaluation order a little, like this:

SetAttributes[rep, HoldFirst]
Attributes[adjust] = HoldFirst
SetAttributes[myFunc, HoldAll]

adjust[a_ /. b_] := Unevaluated@a /. b
rep[a_, b_] := Unevaluated@a /. b

myFunc[inVar_] := Module[{newData}, newData = 1 + inVar; HoldPattern[inVar] -> newData]

x = 1;

myOut = myFunc[x]
(* HoldPattern[x] -> 2 *)

(* Solution 1 *)
(x + a + 100)~rep~myOut
(* 102 + a *)

(* Solution 2 *)
(x + a + 100) /. myOut // adjust
(* 102 + a *)
$\endgroup$
1
  • $\begingroup$ oh, another delayed function, interesting! $\endgroup$ Oct 8, 2016 at 13:58
0
$\begingroup$

I am not sure if I still understand your question properly. I will delete it later if it is completely irrelevant.

Let there be a function

tab[x_] := # x & /@ Range[5]

which gives an list for a variable

tab[g]

{g, 2 g, 3 g, 4 g, 5 g}

Now I define a new function

lin[f__] := Variables[f][[1]] -> f

Which gives you the result as rule

lin[tab[x]]

x -> {x, 2 x, 3 x, 4 x, 5 x}

$\endgroup$
4
  • $\begingroup$ Thanks for the reply, I think it's very relevant! Although it doesn't really solve my problem, it's another good trick to get the variable's name. My bad, I need to revise my original post. $\endgroup$ May 9, 2016 at 17:51
  • $\begingroup$ Taking your code, if x is already assigned, say x = 1, then Variables[ ] will not be able to get the symbol. $\endgroup$ May 9, 2016 at 17:55
  • $\begingroup$ I would like to have a robust module that prints the variable name as a symbol in a rule, just like Solve[ lhs == rhs, x ] will give you x -> sol regardless of there being a global x = 1 or not. $\endgroup$ May 9, 2016 at 17:58
  • $\begingroup$ We can either copy or paste the output from Solve[ ], or use % or Out[ ] to directly apply the rule to an expression. If after fetching the variable name I print it as a string, then even though as the OutputForm the quotes are invisible, it's actually "x" -> sol , and this rule doesn't apply to the variable x. $\endgroup$ May 9, 2016 at 18:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.