3
$\begingroup$

I make heavy use of Out in Mathematica's notebook environment. When I get a computation to work, it will often be spread across multiple cells and lines with %'s and %%'s littered throughout. Thereafter, if I want to use the code as a kind of script (say, I want to iterate over values of some variable with Do), I have to go back and locate all the %'s and give them variable names or else refactor multiple lines of code into one, typically much less readable line of code. Is there any way to avoid doing this extra work?

I will give an example of what would be nice, if it in fact worked. Say I have the following computation:

Cos[1.0]/2;
ArcTan[%];
E^-%^2

and I decide I want to iterate over different values of the argument that appears in the cosine. I'd like to be able to just write:

results = {}
Do[
 Cos[w]/2;
 ArcTan[%];
 results = results~Join~{E^-%^2},
 {w, {1.0, 2.0, 3.0}}
 ]

and have in results the list of values {0.93275, 0.958788, 0.809559}.

I know I can do this:

results = {}
Do[
 w1 = Cos[w]/2;
 w2 = ArcTan[w1];
 results = results~Join~{E^-w2^2},
 {w, {1.0, 2.0, 3.0}}
 ]

but in practice this amounts to a lot of busywork. Also it ultimately negates any time or mental overhead saved by using % as soon as I have need to use the code in any program.

Also, sorry if this has already been asked. It is quite difficult to search for Out and %.

$\endgroup$
3
  • 1
    $\begingroup$ "spread across multiple cells and lines" suggests a lot of mental overhead no matter what, to my imagination. -- Side note. Tip from @Szabolcs/@LeonidShifrin for accumulating results in a linked list in an iterative process: ClearAll[RES]; results = Sequence[]; Do[ val = {k^3, k^2}; results = RES[results, val], {k, -4, 4}]; Echo[results, "Linked list"]; results = List @@ Flatten[results]; Echo[results, "Flattened"]; ListLinePlot[results]. If you have a lot of data, this way is more efficient. $\endgroup$ Commented May 11 at 15:21
  • $\begingroup$ I think you misunderstand how CompoundExpression interacts with Out. For example, 1; 2; 3; is a shorthand for CompoundExpression[1, 2, 3] and is a single expression that only gets assigned a single Out number. You cannot refer to previous results within the same compound expression. For example, 2; % + 7 does not give 9 because the % does not refer to the 2, but rather to the expression that was executed before this one. $\endgroup$ Commented May 11 at 17:22
  • $\begingroup$ @Roman the behavior of CompoundExpression has changed over time... certainly I don't pretend to understand how it works in the evaluation sequence. But I thought-- apparently incorrectly-- that I'd communicated the desired result clearly. $\endgroup$ Commented May 13 at 0:53

3 Answers 3

10
$\begingroup$

Okay, I'd really like to tell you to just not program that way at all. You seem to want to avoid busywork, but I don't think you realize how much busywork you are creating for yourself by programming this way. In this kind of forum, I don't know how to make a case that is both persuasive and pithy, so I'll just provide options for your consideration.

You can avoid proliferation of variables for storing intermediate results:

results = {};
Do[
  temp = Cos[w]/2;
  temp //= ArcTan;
  results = results~Join~{E^-temp^2},
  {w, {1.0, 2.0, 3.0}}]

You can use more idiomatic iterative structures:

Table[E^-(ArcTan[Cos[w]/2])^2, {w, {1., 2., 3.}}]

Array[N[E^-(ArcTan[Cos[#]/2])^2] &, 3]

You can leverage listability or mapping

E^-(ArcTan[Cos[{1.0, 2.0, 3.0}]/2])^2

E^-(ArcTan[Cos[#]/2])^2 & /@ {1.0, 2.0, 3.0}

You could also create a custom function or an explicit composite function "object".

I don't think there is a safe and predictable way to use Out within a procedure, or in particular the body of a Do.

$\endgroup$
1
  • $\begingroup$ Where is your improvisational spirit? 😉 $\endgroup$ Commented May 11 at 20:33
8
$\begingroup$

You are creating a lot of extra work by not taking advantage of functional programming.

You computation has 3 steps with you seem to want to keep separate.

comp = {Cos[#]/2 &, ArcTan, E^-#^2 &};

You only need Fold and a pure function to calculate along this path. For example:

ClearAll[x];
Fold[#2@#1 &, x, comp]
E^-ArcTan[Cos[x]/2]^2

With a vector w values to compute on,

w = {1.0, 2.0, 3.0};

then Map Fold over w

results = Fold[#2@#1 &, #, comp] & /@ w
{0.93275, 0.958788, 0.809559}

With functional programming the number of computational steps can vary, add more functions to comp, and your code remains unchanged. Also, Do is procedural so you are missing out on the vectorised benefits of Wolfram. Not to mention, fewer lines of very readable code with the functional approach.

Note there are other methods that forgo creating pure functions like

Composition[Sequence @@ Reverse[comp]] /@ w
{0.93275, 0.958788, 0.809559}

Likely some others as well.

Hope this helps.

$\endgroup$
0
2
$\begingroup$

Indeed, this can be done but one must think outside the BoxData.

ClearAll[Script,CreateScript];

Script=CreateDocument[Cell[BoxData[""],"Input"],WindowSelected->False,Visible->False];

CreateScript[w_]:=CreateDocument[

Cell[BoxData[{RowBox[{RowBox[{RowBox[{"Cos","[",ToString[w],"]"}],"/","2"}],";"}],"
",RowBox[{RowBox[{"ArcTan","[","%","]"}],";"}],"
",SuperscriptBox["E",RowBox[{"-",SuperscriptBox["%","2"]}]]}],"Input",CellLabel->"In[53]:="],

Script,

WindowSelected->False,Visible->False
]

results=Table[
 NotebookEvaluate[CreateScript[w]],
 {w, {1.0, 2.0, 3.0}}
 ]

The first expression in CreateDocument is just the copy-pasted cell expression of the code already written, with the first instance of "1.0" replaced by ToString[w].

It still requires some manual inspection to go into the Cell and replace the argument of the procedure with ToString[w] in order to define CreateScript, which is a little clunky. However this is linear in programmer-time with the number of arguments the procedure is destined to accept, rather than the number of lines of code or uses of %, %%, %%%, etc.

$\endgroup$
2
  • 4
    $\begingroup$ Wow this is crazy… $\endgroup$ Commented May 12 at 2:02
  • $\begingroup$ I am a little surprised to see the other responses got any points besides the ones I gave out of courtesy. They did not answer the question. $\endgroup$ Commented May 13 at 0:50

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.