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

functions - Get leading series expansion term?

Given a function f[x] , I would like to have a function leadingSeries that returns just the leading term in the series around x=0 . For example: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x)] x and leadingSeries[(1/x + 2 + (1 - 1/x^3)/4)/(4 + x)] -(1/(16 x^3)) Is there such a function in Mathematica? Or maybe one can implement it efficiently? EDIT I finally went with the following implementation, based on Carl Woll 's answer: lds[ex_,x_]:=( (ex/.x->(x+O[x]^2))/.SeriesData[U_,Z_,L_List,Mi_,Ma_,De_]:>SeriesData[U,Z,{L[[1]]},Mi,Mi+1,De]//Quiet//Normal) The advantage is, that this one also properly works with functions whose leading term is a constant: lds[Exp[x],x] 1 Answer Update 1 Updated to eliminate SeriesData and to not return additional terms Perhaps you could use: leadingSeries[expr_, x_] := Normal[expr /. x->(x+O[x]^2) /. a_List :> Take[a, 1]] Then for your examples: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x), x] leadingSeries[Exp[x], x] leadingSeries[(1/x + 2 + (1 - 1/x...

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...

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-...