Skip to main content

programming - How do I evaluate only one step of an expression?



I am looking for a simple, robust way to evaluate an expression only one step, and return the result in a held form.


The definition of a single step is ambiguous, and this itself is probably worthy of exploration. Some interpretations will raise the question of what should be returned. I am specifically thinking of capturing the right-hand side of function definitions and rules. Another view would be the first evaluation step that transforms the entire input expression.


Examples of desired output:


x = 1; y = 1;
q := 1 + 2 x + 3 y

(* step[q] -----> HoldForm[1 + 2 x + 3 y] *)

val = 1;
f[x_] /; x < 5 := ("X < 5"; val)

f[_, y_] := y val
f[x_] := f[x - 1]

(* step[ f[3] ] -----> HoldForm["X < 5"; val] *)
(* step[ f[3, 4] ] -----> HoldForm[4 val] *)
(* step[ f[5] ] -----> HoldForm[f[5 - 1]] *)

For an internal function:


x = 7; y = 4;


(* step[ Mod[x Pi, y] ] -----> HoldForm[ Mod[7 Pi, 4] ] *)
(* step[ Mod[7 Pi, 4] ] -----> HoldForm[ 7 Pi - Quotient[7 Pi, 4] 4 ] *)

each because that is the first step in Trace that transforms the entire expression.


I realize that for user-defined functions it is possible to manipulate *Values manually, but finding and matching all possible *Values is complicated, and I am looking for a universal approach using something like TraceScan. Trace keeps track of the level of evaluation with brackets, but TraceScan does not appear to provide this information to its given functions. It would be possible to use Trace and then extract the desired step afterward, but I want something that does not carry out the rest of the evaluation.



Answer



I believe I have found the solution I was seeking. It returns the first step that transforms the entire expression, and it does so without further evaluation.


The P = (P = part is to skip the untransformed expression.


SetAttributes[step, HoldAll]


step[expr_] :=
Module[{P},
P = (P = Return[#, TraceScan] &) &;
TraceScan[P, expr, TraceDepth -> 1]
]

I hope that this function will be as helpful to others as I expect it will be to me.


Comments

Popular posts from this blog

front end - keyboard shortcut to invoke Insert new matrix

I frequently need to type in some matrices, and the menu command Insert > Table/Matrix > New... allows matrices with lines drawn between columns and rows, which is very helpful. I would like to make a keyboard shortcut for it, but cannot find the relevant frontend token command (4209405) for it. Since the FullForm[] and InputForm[] of matrices with lines drawn between rows and columns is the same as those without lines, it's hard to do this via 3rd party system-wide text expanders (e.g. autohotkey or atext on mac). How does one assign a keyboard shortcut for the menu item Insert > Table/Matrix > New... , preferably using only mathematica? Thanks! Answer In the MenuSetup.tr (for linux located in the $InstallationDirectory/SystemFiles/FrontEnd/TextResources/X/ directory), I changed the line MenuItem["&New...", "CreateGridBoxDialog"] to read MenuItem["&New...", "CreateGridBoxDialog", MenuKey["m", Modifiers-...

How to thread a list

I have data in format data = {{a1, a2}, {b1, b2}, {c1, c2}, {d1, d2}} Tableform: I want to thread it to : tdata = {{{a1, b1}, {a2, b2}}, {{a1, c1}, {a2, c2}}, {{a1, d1}, {a2, d2}}} Tableform: And I would like to do better then pseudofunction[n_] := Transpose[{data2[[1]], data2[[n]]}]; SetAttributes[pseudofunction, Listable]; Range[2, 4] // pseudofunction Here is my benchmark data, where data3 is normal sample of real data. data3 = Drop[ExcelWorkBook[[Column1 ;; Column4]], None, 1]; data2 = {a #, b #, c #, d #} & /@ Range[1, 10^5]; data = RandomReal[{0, 1}, {10^6, 4}]; Here is my benchmark code kptnw[list_] := Transpose[{Table[First@#, {Length@# - 1}], Rest@#}, {3, 1, 2}] &@list kptnw2[list_] := Transpose[{ConstantArray[First@#, Length@# - 1], Rest@#}, {3, 1, 2}] &@list OleksandrR[list_] := Flatten[Outer[List, List@First[list], Rest[list], 1], {{2}, {1, 4}}] paradox2[list_] := Partition[Riffle[list[[1]], #], 2] & /@ Drop[list, 1] RM[list_] := FoldList[Transpose[{First@li...

dynamic - How can I make a clickable ArrayPlot that returns input?

I would like to create a dynamic ArrayPlot so that the rectangles, when clicked, provide the input. Can I use ArrayPlot for this? Or is there something else I should have to use? Answer ArrayPlot is much more than just a simple array like Grid : it represents a ranged 2D dataset, and its visualization can be finetuned by options like DataReversed and DataRange . These features make it quite complicated to reproduce the same layout and order with Grid . Here I offer AnnotatedArrayPlot which comes in handy when your dataset is more than just a flat 2D array. The dynamic interface allows highlighting individual cells and possibly interacting with them. AnnotatedArrayPlot works the same way as ArrayPlot and accepts the same options plus Enabled , HighlightCoordinates , HighlightStyle and HighlightElementFunction . data = {{Missing["HasSomeMoreData"], GrayLevel[ 1], {RGBColor[0, 1, 1], RGBColor[0, 0, 1], GrayLevel[1]}, RGBColor[0, 1, 0]}, {GrayLevel[0], GrayLevel...