Mathematica Stack Exchange is a question and answer site for users of Mathematica. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have been playing with slightly above trivial code manipulations in Mathematica. I thought Mathematica would be great for this kind of work because of rule replacement and expression manipulation, but I have been running in a lot of issues (I am an old lisp programmer and I love manipulating ASTs).

The code generation I am doing is taking DSP expressions like

{ f[x] -> a0 * x + b1 * y z^-1,
  y -> af0 * f[x] + bf1 * f[x] z^-1 + bf2 * f[x] z^-2 }

and transform them to code working on discrete samples by keeping sample delayed values (the values multiplied by z^-n in a ring buffer. The generated code (this is just pseudo code and by no means correct) is of the form:

Module[{ fxRingBuffer = {0, 0}, fxRingBufferIdx = 1,
         yRingBuffer = {0}, yRingBufferIdx = 1 },
   Function[x, 
      Module[{ fx = a0 * x + b1 * yRingBuffer[...], ...},
         fxRingBuffer[[fxRingBufferIdx]] = fx;
         fxRingBufferIdx = Mod[fxRingBufferIdx + 1, Length[fxRingBufferIdx]; 
         ...
         y]]]

Here is an actual example (see the link to the full code at the bottom):

expRecurseMakeFunction[{y → Expand@Simplify[x a0 + y z-1 b]}]

Hold[Module[{yrb$8738 = {0}, yidx$8739 = 1}, Function[x, Module[{ycur$8740},
    Sequence[{ycur$8740 = a0 x + b1 yrb$8738〚1 + Mod[-2 + yidx$8739, 1]〛}];
    Sequence[yrb$8738〚yidx$8739〛 = ycur$8740, yidx$8739 = 1 + Mod[yidx$8739, 1]];
ycur$8740]]]]

The approach I am taking is to use a template like this:

Hold[Module[ringBufferInitialization, 
    Function[x, 
       Module[{sampleUpdates},
          ringBufferUpdates;
          y]]]

and then doing code replacement. The problems I have been having is how to have the code I generate not be evaluated. I have reduced the issues to two toy examples. The first one is generating a list of Set[var, val] assignments to be plugged into ringBufferInitialization and sampleUpdates above. The approach I have taken is to generate MySet forms that are replaced by Set once they are safe inside the toplevel Hold:

generateAssignments[symbols_, values_] :=
  Hold[Module[assignments,
     someBody[]]] //. {
    assignments -> MapThread[MySet, {symbols, values}],
    MySet -> Set
    };

For example:

ClearAll[a, b, c, d];
generateAssignments[{a, b, c, d}, {1, 2, 3, 4}]

Hold[Module[{a = 1, b = 2, c = 3, d = 4}, someBody[]]]

Is there a better way to do this?

The other issue is replacing code inside forms with a Hold* attribute. For example, if any of my functions have the form If[], replacing variable access with the form to access the ring buffers won't evaluate properly and cause problems. Here my solution is really half-baked, as I just replace my If[] blocks with Piecewise[], which worked for my usecase. Again a toy example:

useLookupTable[body_, symbolMap_] :=
 body /. lookupForm[a_, idx_] :> symbolMap[a][[idx]]

useLookupTable[Hold[If[a > 1, lookupForm[b, 23], lookupForm[c, 24]]],
 <|a -> aLookup, b -> bLookup|>]

Hold[If[a > 1, <|a -> aLookup, b -> bLookup|>[b][[
   23]], <|a -> aLookup, b -> bLookup|>[c][[24]]]]

I was looking forward to manipulating my AST, but fighting the evaluation order was pretty frustrating, and I feel like I am missing some general mechanism (like the lisp quasiquote + splicing reader macros) to handle this case.

Here is a link to the (very hacky...) full code: wavefolder DSP analysis

Edit:

Here is an approach using Inactive which seems nice:

generateAssignments[symbols_, values_] :=
  Hold[Module[assignments,
      Print[a, b, c, d]]] //. {
     assignments -> MapThread[Inactive[Set], {symbols, values}]
     } // Activate;
share|improve this question
    
Sorry about the two questions, I feel they are actually the same. The problem with the example I posted is that if I generate the Set[a, 1] on its own, I will end up with a being assigned, instead of it being replaced verbatim into my Hold[] template. – Manuel Odendahl Jan 3 at 15:22
    
The Inactive indeed seems like a good way to handle this (see my edit). This leaves me with the second part (replacing code in Hold forms), which I can extract to another question. – Manuel Odendahl Jan 3 at 15:53
    
It seems to me that this question is a rather straightforward duplicate of either (3864), (28610), or (31708) for the first part and (29317) for the second, with maybe a reference to (20328) (basic) and (2352) (advanced). Nevertheless I am glad the respondents saw it otherwise. – Mr.Wizard Jun 15 at 15:43
up vote 14 down vote accepted

I think, your question is as much about techniques of evaluation control, as it is about code generation. I will show several different methods to achieve the first result you asked for, which would illustrate different approaches and techniques of evaluation control.

Working with unevaluated parts

You can, if you want to, work with parts of your expression, carefully avoiding evaluation leaks. This method is perhaps one of the most difficult and least economical, since it requires a good knowledge of evaluation control, and even then can be tedious and error-prone, if one doesn't stay really focused.

I will first show the solution step by step, and then assemble it into a function. We will start with the lists of variables and values, but first let us give some of the variables some global values, to test that our solution will not capture global bindings:

ClearAll[a, b, c, d];
a = 10;
b = 20;
{{a, b, c, d}, {1, 2, 3, 4}}

(* {{10, 20, c, d}, {1, 2, 3, 4}} *)

The idiom with MapThread that you suggested is a good one, and we will use it. But not with Set directly. We could use a temporary wrapper, and replace it with Set afterwards, but I will pick a different road. Here is what we would like to do:

MapThread[Hold[#1 = #2] &, {{a, b, c, d}, {1, 2, 3, 4}}]

(* {Hold[10 = 1], Hold[20 = 2], Hold[c = 3], Hold[d = 4]} *)

But this doesn't work. The first step in the right direction will be to insert Unevaluated:

MapThread[Hold[#1 = #2] &, Unevaluated@{{a, b, c, d}, {1, 2, 3, 4}}]

(* {Hold[10 = 1], Hold[20 = 2], Hold[c = 3], Hold[d = 4]} *)

This, however, is not good enough. The premature evaluation happens also in Function during the parameter-passing stage, and thus we need this:

step1 = MapThread[
  Function[Null, Hold[#1 = #2], HoldAll], 
  Unevaluated @ {{a, b, c, d}, {1, 2, 3, 4}}
]

(* {Hold[a = 1], Hold[b = 2], Hold[c = 3], Hold[d = 4]} *)

We are good now, but what we need is we need is single Hold around an assignment list, while we have a List of assignments each wrapped in individual Hold. The useful trick here is to use Thread[#, Hold]&, so that:

step2 = Thread[#, Hold] &@step1

(* Hold[{a = 1, b = 2, c = 3, d = 4}] *)

This is closer to what we need, but now we want to wrap Module around the variable / assignment list, and get it into Hold. One of the simplest ways to do this is by using rules, which would be a version of a so-called injector pattern:

step3 = Replace[step2, Hold[a_List] :> Hold[Module[a, someBody[]]]]

(* Hold[Module[{a = 1, b = 2, c = 3, d = 4}, someBody[]]] *)

which is the final result.

As a function, the resulting code would look like this:

ClearAll[genMT];
SetAttributes[genMT, HoldAll];
genMT[vars : {___Symbol}, vals_List] :=
  Composition[
    Replace[Hold[a_List] :> Hold[Module[a, someBody[]]]],
    Thread[#, Hold] &
  ] @ MapThread[
    Function[Null, Hold[#1 = #2], HoldAll],
    Unevaluated @ {vars, vals}
  ]

Where I used an operator form for Replace. So, for example, we have

genMT[{a, b, c, d}, {1, 2, 3, 4}]

(* Hold[Module[{a = 1, b = 2, c = 3, d = 4}, someBody[]]] *)

Note that this method is hard. We had to use several advanced techniques (evaluation control, a trick with Thread, injector pattern) in combination. I have shown this method to illustrate the "brute-force" approach, which is certainly possible, but is not the most economical or elegant one. One reason why this approach is hard is that we don't use rules and pattern-matching to the full extent.

Using holding symbolic containers for expression transformations

There is an alternative way to build an expression we need. I frequently find it more convenient than other methods, since it often gives you more control, and makes it easier to control evaluation.

The method is to replace iteration (where it is necessary) with recursion, and use symbolic containers with Hold* attributes to transform unevaluated expressions into suitable form. For the case at hand, it may look like this:

ClearAll[a, b, c, d, gen];
SetAttributes[gen, HoldAll];
gen[vars : {___Symbol}, vals_List] := gen[{}, vars, vals];
gen[{a___}, {v_, rvars___}, {val_, rvals___}] :=
  gen[{a, Set[v, val]}, {rvars}, {rvals}];
gen[a_List, {}, {}] := Hold[Module[a, someBody[]]]; 

We can test:

a = 1;
b = 2;
gen[{a, b, c, d}, {1, 2, 3, 4}]

(* Hold[Module[{a = 1, b = 2, c = 3, d = 4}, someBody[]]] *)

The way this works is that gen function gradually picks elements from lists of variable names and values and accumulates the assignments built out of them. When the lists are exhausted, we obtain a list of assignments in an unevaluated form, and can then generate the code we need, straightforwardly.

Using Block trick

The method I will describe here is completely different. It is based on the ability of Block to make (almost) any symbol "forget" its definitions temporarily. This may be used to non-trivially change the evaluation order. For the case at hand, it will be one of the most economical methods.

Here is the code:

ClearAll[genB];
SetAttributes[genB, HoldAll];
genB[{vars___Symbol}, vals_List] :=
  Block[{vars, Set, Module, Hold},
    SetAttributes[Module, HoldRest];
    Hold[Module[MapThread[Set, {{vars}, vals}], someBody[]]]
  ]

The way this works is that it temporarily switches off the standard behavior of Set, Module, and Hold, making them just symbolic wrappers during the evaluation of the body of the Block. This is what we need here for code generation. I had to attach a temporary HoldRest to Module inside Block, so that the body of the Module (someBody[]) is kept unevaluated.

We can test:

genB[{a, b, c, d}, {1, 2, 3, 4}]

(* Hold[Module[{a = 1, b = 2, c = 3, d = 4}, someBody[]]] *)

More advanced techniques

One can base more formal, universal and advanced techniques on methods I have described above, by generalizing and automating them to fit one's needs.

For example, some time ago I've developed code generator based on the generalized Block trick used above. The seriously simplified version of this technique I posted here, and with the help of the FrozenCodeEval function defined there, the solution to your problem becomes trivial:

FrozenCodeEval[
  Hold[Module[MapThread[Set, {{a, b, c, d}, {1, 2, 3, 4}}], someBody[]]],
  {MapThread}
]

(* Hold[Module[{a = 1, b = 2, c = 3, d = 4}, someBody[]]] *)

basically, here you just tell FrozenCodeEval, which heads should evaluate (in this case, only MapThread), and all the rest are kept "frozen". This technique I have also illustrated (among some others) in this answer.

Another possible (but IMO somewhat less powerful) technique is to use rules. I have illustrated this technique in this answer.

Yet another technique can be based on generalizing the holding symbolic container approach I described above. One good example of this approach is the LetL macro (nested With replacement), which is described in this answer, and particularly its more complex extension. This method is the one I've preferred recently.

One can also base code generation on introducing several (many) inert heads (like mySet), and replacing them with some "actual" heads (like Set) at the end, after the code has been generated. This was one of your original suggestions, and is certainly also a possibility.

Finally, one may implement a macro system, which would provide macros in a way similar to Lisp. However, that would require introducing read-time, which currently sort-of exists (parsing code to expressions), but can't really be used much. This is possible to do if one implements an alternative code loader, that would parse code to symbolic expression and give the user access to that parsed code before actually evaluating it.

Why I think that Inactive is in general not an answer

This is certainly an opinionated topic, but I personally did not see (almost) any case where Inactive would solve a problem of evaluation control (outside math-related functionality), in a way that would be simpler than other means of evaluation control.

From the viewpoint of evaluation control, the problem of Inactive is that while it inactivates a given head, it does not hold the arguments of that head, so they can freely evaluate. And the effort needed to prevent them from doing so will most of the time invalidate all the benefits of using Inactivate, as compared to Hold, Unevaluated etc.

For example, in our case (taking your code):

Hold[Module[assignments, Print[a, b, c, d]]] //. {
  assignments -> MapThread[Inactive[Set], {{a, b, c, d}, {1, 2, 3, 4}}
]} // Activate

(* Hold[Module[{10 = 1, 20 = 2, c = 3, d = 4}, Print[a, b, c, d]]] *)

shows that the global bindings to a and b were picked up in this method. And avoiding that will make the code no less complex than the first alternative I have shown above.

Summary

There exist several (many) techniques, allowing one to dynamically generate Mathematica code. The ones I have illustrated are based on

  • Direct manipulations with unevaluated parts of expressions
  • Using symbolic holding containers for expression transformations
  • Using Block trick

One can come up with more advanced / general / universal frameworks for code generation. The ones I mentioned are based on

  • Block trick (code "freezing")
  • Symbolic holding containers
  • Repeated rule application to held expressions
  • Inert intermediate (temporary) heads
  • (Read-time) macros

Which one to use depends on the case. For simple cases, some of the simpler techniques may be just enough. If you need to routinely generate code, you may be better off with some heavier but more general and systematic approach.

share|improve this answer
    
thank you so much. – Manuel Odendahl Jan 3 at 19:48
    
@ManuelOdendahl Well, thanks, accepting within a few seconds of me posting an answer is impressive, but perhaps you could wait for a bit to at least read it - who knows, may be I got tired and posted a load of junk ... – Leonid Shifrin Jan 3 at 19:50
    
uh i am a bit new to asking questions here, i must have clicked on it without knowing what it would do. thanks again, i read through the answer and it is indeed spot on. – Manuel Odendahl Jan 4 at 7:32
1  
@ManuelOdendahl Don't take is seriously, I was just kidding :). Actually, a good practice when asking / accepting a best answer is to give answerers some time (like half a day, a day or two) to answer before marking some answer as accepted, even if you have some really good answers already - because that would encourage others to contribute. But this is entirely up to the asker, and you can of course accept the answer you like any time you want. – Leonid Shifrin Jan 4 at 14:57
    
If I had seen this question back in January I would probably just have closed it with multiple references in the comments (see e.g. my comment above) but I am glad instead that you wrote this. You once again think to cover angles that don't even occur to me. – Mr.Wizard Jun 15 at 15:48

Since OP mentions Lisp quasiquote mechanism, maybe we can implement something similar in Mathematica.

Disclaimer: I've never written a line of code in any of Lisp dialects.

In Mathematica rules for evaluation of an expression are "attached" to symbols in this expression through various ...Values and Attributes (evaluation of many built-in symbols is implemented in lower level than ...Values but still it's "attached" to the symbol). To prevent evaluation of expression we don't need to hold whole expression, it's enough to "isolate" all symbols inside expression. This "isolation" can be achieved by wrapping symbol with some other symbol for which we know that it will remain unevaluated.

If we take

ClearAll[a, b, c, f, g]
expr = f[a, g[b]][c]

expression and wrap f with some head, let's say quoted:

quoted[f][a, g[b]][c]

we will prevent usage of f's DownValues, SubValues and Attributes, which like e.g. Orderless also can rewrite expression. If we add HoldFirst, HoldAll, or HoldAllComplete attribute to quoted we will prevent usage of f's OwnValues, but to be sure that any of f's UpValues that could match quoted[f] also won't be used we choose HoldAllComplete.

To prevent any evaluation in above expression we can wrap all symbols with quoted:

quotedExpr = quoted[f][quoted[a], quoted[g][quoted[b]]][quoted[c]]

This expression has the same structure as "non-quoted" expression in the sense that at each Part of "quoted" expression is quoted version of the same Part from "non-quoted" expression, for example Part 1 or 0, 2:

expr[[1]]
quotedExpr[[1]]
(* c *)
(* quoted[c] *)

expr[[0, 2]]
quotedExpr[[0, 2]]
(* g[b] *)
(* quoted[g][quoted[b]] *)

If we want some parts of our expression to be evaluated, we can easily mix "quoted" symbols with "non-quoted" ones, which is the main advantage of this approach over wrapping whole expression with single holding wrapper.

Of course manual wrapping of all symbols with quoted would be tedious, so we can define function quote that will do this automatically. Since often we want to quote whole expression except some parts, that we want to evaluate, we can define quasiquote function that quotes every symbol except those inside expression with head unquote.

Since version 10, Mathematica has similar mechanism built-in. We can Inactivate expressions, but, as Leonid mentioned in his answer, it'll inactivate (wrap with Inactive head) only symbols that are heads of expressions. We can overcome this limitation by defining own functions wrapping all symbols with Inactive. Advantage of this approach, over custom quoted symbol, is that Matematica provides IgnoringInactive function which simplifies matching/replacing parts of inactive expressions. But there are few disadvantages. Inactive has HoldFirst and not HoldAllComplete attribute so there is a possibility of evaluation leak through UpValues. It was designed only for heads of expressions and when used for non-heads its formatting is inconsistent. Since inactivation serves slightly different purposes, mixing it with quoting may be a bad idea. Nonetheless implementation based on Inactive is available in second revision of this answer.

Implementation

Core functions

Core of the system is based on following four functions and quoted head:

quote replaces all symbols (except excluded ones) by symbols wrapped with quoted. Expressions, matching pattern given as value of "ExcludedForms" option, are not quoted. It accepts optional second argument used as pattern for expressions that will be excluded in addition to ones matching pattern from option.

quasiquote works like quote, but, by default, doesn't quote expressions with head unquote.

unquote is head used to mark parts, of quasiquote expressions, that shouldn't be quoted.

eval wraps expression with head taken from "Head" option, with default being Identity, and strips quoted wrappers.

ClearAll[quote, quasiquote, unquote, eval, quoted]

SetAttributes[{quote, quasiquote, unquote, quoted}, HoldAllComplete]

Options[quote] = {
    "ExcludedForms" -> 
        List | Rule | RuleDelayed | Hold | HoldComplete | HoldForm | 
        Slot | SlotSequence | Alternatives | Default | Blank | 
        BlankSequence | BlankNullSequence | Except | Optional | Pattern |
        PatternTest | PatternSequence | Repeated | RepeatedNull | 
        Longest | Shortest | Verbatim | HoldPattern | OptionsPattern | 
        IgnoringInactive |
        _quoted | _CompiledFunction | _Experimental`NumericalFunction |
        _InterpolatingFunction | _BSplineFunction | _BezierFunction |
        _ParametricFunction | _NDSolve`StateData |
        _NDSolve`FiniteDifferenceDerivative | _BooleanFunction | _Root |
        _AlgebraicNumber | _DifferenceRoot | _DifferentialRoot | _FittedModel |
        _DataDistribution | _SurvivalModel | _NearestFunction |
        _LinearSolveFunction | _Image | _Image3D | _StateSpaceModel |
        _TransferFunctionModel | _Graphics | _Graphics3D | _GraphicsComplex |
        _Point | _Line | _Polygon | _Directive | _TemporalData | _CellObject |
        _ColorDataFunction | _ColorProfileData | _ByteArray | _CoxModel |
        _EventData | _HypothesisTestData | _LibraryFunction |
        _LiftingFilterData | _NotebookObject | _OptimumFlowData |
        _SeriesData | _StructuredArray | _WeightedData,
    "ExtraRules" -> {}
};
quote[expr_,
    extraExclusion : Except[_?OptionQ] | PatternSequence[],
    opts___?OptionQ
] :=
    Unevaluated[expr] /. Flatten@{
        OptionValue[quote, {opts}, "ExtraRules"],
        excluded :
            extraExclusion | OptionValue[quote, {opts}, "ExcludedForms"] :>
                excluded,
        sym : Except[HoldPattern@Symbol[___], _Symbol] :> quoted[sym]
    }

quasiquote[expr_,
    extraExclusion : Except[_?OptionQ] | PatternSequence[],
    opts___?OptionQ
] :=
    quote[expr, extraExclusion | _unquote, opts]

unquote[expr_] := expr

Options[eval] = {"Head" -> Identity, "Pattern" -> _};
eval[expr_, opts___?OptionQ] :=
    OptionValue[eval, {opts}, "Head"][expr] /. 
        HoldPattern[quoted][x : OptionValue[eval, {opts}, "Pattern"]] :> x

Utilities

Additional functions that simplify matching/replacing parts of quoted expressions and help with evaluation control.

quoteNonPattern is like quasiquote but, additionally, leaves parts of expressions, that have special meaning in pattern matching, non-quoted.

quoteEvaluated first evaluates given expression, then quotes result. It accepts optional second argument that controls how many "evaluation steps" are performed before quoting, this functionality is inspired by Mr.Wizard's step function.

quoted has some formatting defined (quoted symbols have LightGray backgrounds), for Mathematica versions >= 10 we piggyback on formatting of Inactive to get nice formatting for quoted versions of functions like Plus or Set.

ClearAll[quoteNonPattern, quoteEvaluated]

SetAttributes[{quoteNonPattern, quoteEvaluated}, HoldAllComplete]

quoteNonPattern[expr_,
    extraExclusion : Except[_?OptionQ] | PatternSequence[],
    opts___?OptionQ
] :=
    Quiet[
        quasiquote[expr,
            extraExclusion | Alternatives | Except | HoldPattern | 
            IgnoringInactive | Literal | Longest | Optional | 
            OrderlessPatternSequence | PatternSequence | RepeatedNull | 
            Shortest | _Blank | _BlankNullSequence | _BlankSequence |
            _OptionsPattern
            ,
            "ExtraRules" -> {
                OptionValue[quote, {opts}, "ExtraRules"],
                (h : Condition | PatternTest | Repeated)[patt_, rest___] :> 
                    h[quoteNonPattern[patt, extraExclusion, opts], rest],
                Verbatim[Pattern][name_, patt_] :> 
                    Pattern[name, quoteNonPattern[patt, extraExclusion, opts]],
                Verbatim[Verbatim][verb_] :> 
                    Verbatim@quasiquote[verb, extraExclusion, opts]
            },
            opts
        ],
        RuleDelayed::rhs
    ]


quoteEvaluated[expr_,
    (steps_ /; steps === Infinity) | PatternSequence[],
    (extraExclusion_ /; !IntegerQ[extraExclusion] && !OptionQ[extraExclusion]) |
        PatternSequence[],
    opts___?OptionQ
] :=
    quote[#, extraExclusion, opts] &@expr
quoteEvaluated[expr_, 
    steps_ /; steps === 0,
    (extraExclusion_ /; !IntegerQ[extraExclusion] && !OptionQ[extraExclusion]) |
        PatternSequence[], 
    opts___?OptionQ
] :=
    quote[expr, extraExclusion, opts]
quoteEvaluated[expr_,
    steps_ /; IntegerQ[steps] && Positive[steps],
    (extraExclusion_ /; !IntegerQ[extraExclusion] && !OptionQ[extraExclusion]) |
        PatternSequence[], 
    opts___?OptionQ
] :=
    (* Based on: http://mathematica.stackexchange.com/a/1447/14303 *)
    Module[{i = 0, tag},
        Catch[
            quote[#, extraExclusion, opts]& @ TraceScan[
                If[i++ >= steps, Throw[#, tag]]&,
                Unevaluated[expr],
                TraceDepth -> 1
            ],
            tag,
            (* TODO: When TraceScan encounters Evaluate[...] expression, 
               it passes to function, from its first argument,
               HoldForm[HoldForm[Evaluate][...]],
               so we should remove not only external HoldForm,
               but also the one directly wrapping Evaluate,
               but the same expression is passed when TraceScan encounters
               HoldForm[Evaluate][...],
               where we should remove only external HoldForm.
               How can we distinguish these two situations? *)
            First@quote[#1, extraExclusion, opts] &
        ]
    ]


$quotedStyle = {Background -> LightGray};

If[$VersionNumber >= 10,
    ClearAll[inactiveToQuoted];
    SetAttributes[inactiveToQuoted, HoldAllComplete];
    inactiveToQuoted[Inactive[h_][args___]] := quoted[h][args];
    inactiveToQuoted[expr_] := expr;

    quoted /: MakeBoxes[quoted[h_Symbol][args___], StandardForm] :=
        With[{$quotedStyle = $quotedStyle},
            TagBox[
                MakeBoxes[Inactive[h][args], StandardForm] /. {
                    (Tooltip -> tooltip_String /;
                        StringMatchQ[tooltip, "Inactive[*]"]) :>
                            (Tooltip -> "quoted" <> StringDrop[tooltip, 8]),
                    (BaseStyle -> "Inactive") -> (BaseStyle -> $quotedStyle),
                    StyleBox[boxes_, "Inactive"] :>
                        StyleBox[boxes, $quotedStyle]
                },
                inactiveToQuoted
            ]
        ]
 ]
 quoted /: MakeBoxes[quoted[x_Symbol], StandardForm] := 
     TagBox[
         MakeBoxes[x, StandardForm],
         quoted,
         BaseStyle -> $quotedStyle, SyntaxForm -> "Symbol",
         Tooltip -> ToString[quoted[x], InputForm]
     ]

Usage examples

Example of quoted expression, we define function h and variable x to show that their evaluation is properly held:

ClearAll[f, g, h, b, x]
x = 5;
h[x_] := 2 x

quasiquote@{
    1 + 2 + x,
    unquote@{(* this part is unquoted, so it'll be evaluated *)
        3 + 4,
        quasiquote@{(* this part is quoted again so it won't be evaluated *)
            5 + 6,
            unquote[7 + 8] (* and this will evaluate *)
        },
        quote@{(* this won't evaluate *)
            9 + 10,
            (* following will also not evaluate,
               since it's inside quote not quasiquote *)
            unquote[11 + 12]
        }
    },
    # + 1 &[3],
    f[g[x]][h[b]]
}
% // eval
(* {
       1 + 2 + x,
       {
           7,
           {5 + 6, 15},
           {9 + 10, unquote[11 + 12]}
       },
       (#1+1&)[3],
       f[g[x]][h[b]]
   } *)
(* {8, {7, {11, 15}, {19, 23}}, 4, f[g[5]][2 b]} *)

Example of generation of code of Module from OP:

ClearAll[a, b, c, d]
a = 1;
b = 2;
quotedModuleCode =
    quasiquote@Module[
        unquote[MapThread][Set, {{a, b, c, d}, {1, 2, 3, 4}}],
        Print[a, b, c, d]
    ]
eval[%, "Head" -> HoldComplete]
(* Module[{a = 1, b = 2, c = 3, d = 4}, Print[a, b, c, d]] *)
(* HoldComplete[Module[{a = 1, b = 2, c = 3, d = 4}, Print[a, b, c, d]]] *)

Different variant of generation of the same Module code, this time symbols localized by Module and their values are taken from lists assigned to variables. To make things more difficult some of symbols intended for localization have defined values, so ordinary evaluation of variable with their list won't work. To overcome this problem, we quote said variable after only one step of evaluation.

ClearAll[a, b, c, d, symbols, values]
symbols = {a, b, c, d};
values = {1, 2, 3, 4};
a = 1;
b = 2;

symbols
quotedSymbols = quoteEvaluated[symbols, 1]

quote[Module][
    MapThread[quote@Set, {quotedSymbols, values}],
    quote[Print] @@ quotedSymbols
]
(* {1, 2, c, d} *)
(* {a, b, c, d} *)
(* Module[{a = 1, b = 2, c = 3, d = 4}, Print[a, b, c, d]] *)

Note that in this case simple Extraction of OwnValues: quotedSymbols = Extract[OwnValues[symbols], {1, 2}, quote] would also work.

Lookup table example:

symbolMap = quote[<|a -> aLookup, b -> bLookup|>, Association]
quote@If[a > 1, lookupForm[b, 23], lookupForm[a, 24]] /.
    quoteNonPattern@lookupForm[x_, i_] :> quote[Part][symbolMap[x], i]
(* <|a -> aLookup, b -> bLookup|> *)
(* If[a > 1, bLookup[[23]], aLookup[[24]]] *)

"Quoted" code can be easily manipulated and composed:

quotedFDef = quasiquote[
    f[x_] :=
        unquote[quotedModuleCode /. {
            quoteNonPattern[a = _] :> quote[a = x],
            quoteNonPattern@Print[x_, y_, rest__] :> 
                quasiquote@h[
                    unquote[(2 + 5) x],
                    3 10 y,
                    unquote[Sequence @@ {rest}]
                ]
        }]
]
(* f[Pattern[x, _]] := Module[{a = x, b = 2, c = 3, d = 4}, h[7 a, 3*10*b, c, d]] *)

and, when necessary, evaluated:

ClearAll[f]
eval[quotedFDef]
?? f
(* Global`f
   f[x_]:=Module[{a=x,b=2,c=3,d=4},h[7 a,3 10 b,c,d]] *)

f[z]
(* h[7 z, 60, 3, 4] *)
share|improve this answer
    
+1, it is an interesting technique. But as far as I can tell, you can use any head (perhaps having Hold* or HoldAllComplete attributes) in place of Intactive here - i.e., you don't really use any Inatctive - specific built-in operations (such as Activate, Inactivate). I achieve similar results with the full version of my code-freezing technique, based on the Block trick - with a difference that in my case, "frozen" symbols are hidden by dummy symbols during evaluation, rather than have another head wrapped around them. – Leonid Shifrin Jan 4 at 1:30
1  
Your technique is pretty close to the idea I discussed in this answer, although there I didn't go into as much detail as you did here. B.t.w., the answer of WReach for the same question is also relevant in this context. – Leonid Shifrin Jan 4 at 1:33
    
@Leonid Yes, I could use any head in place of Inactive. I used it for two reasons. 1. IgnoringInactive can be sometimes useful when matching/replacing parts of "quoted" code, but instead of IgnoringInactive one could properly quote relevant pattern (then maybe specialized quotePattern, would be useful, that would not quote Pattern first argument, etc.). 2. Built-in formatting of Inactive makes "quoted" code a bit more readable, though when abused for non-heads it looks inconsistent, but of course for custom head can have custom (more consistent) formatting. ... – jkuczm Jan 4 at 8:43
    
@Leonid When we need "stronger quoting" of HoldAllComplete-type then Inactive is ruled out, and custom head will be a better choice. I've not seen your linked answer before, yes it is basically the same idea, but IMO wrapping only symbols and not whole expressions makes quoted code more wieldy (subexpressions have the same Position as in non-qouted code). – jkuczm Jan 4 at 8:52
1  
Yes, agree on all points. Thanks for replying. Actually, while I experimented with this technique, I may have overlooked its usefulness. In particular, I like the composability of your approach. When at some point I needed similar functionality, I ended up using Block-based technique, because there I could extend symbol (in)activation to the entire execution stack, which was what I needed. However, the technique you propose is safer, since it is based purely on lexical scoping constructs. – Leonid Shifrin Jan 4 at 14:54

I'm very sure you will find answers to all your questions in very detailed form on this site, since the issues you have were already discussed. Please start reading

In general, you should look for answers from Leonid, since he did a great deal of work documenting many meta-programming techniques that show you how you can use Mathematica to create Mathematica code.

As for your two questions, let me give you a short head start. I'm giving x and y values, so that you see that the code still works:

x = 1;
y = 2;

One way to create a held Module is

Function[{vars, body}, Hold[Module[vars, body]], {HoldAll}][{x = 5, y = 6}, x + y + 3]

the other one is defining a separate function for this, like your generateAssignments

SetAttributes[createModule, {HoldAll}];
createModule[vars_, body_] := Hold[Module[{vars}, body]]

createModule[{x = 5, y = 6}, x + y + 3]
(* Hold[Module[{{x = 5, y = 6}}, x + y + 3]] *)

Both works find and crucial is that both function hold their arguments which means that the variable definition and the body is not evaluated during the call.

As for your second problem, please search for the Trott-Strzebonski trick for in-place evaluation. That being said, I made a small change to your definition:

useLookupTable[body_, symbolMap_] := 
 body /. lookupForm[a_, idx_] :> 
   With[{eval = symbolMap[a][idx]}, eval /; True]

useLookupTable[
 Hold[If[a > 1, lookupForm[b, 23], lookupForm[a, 24]]], <|
  a -> aLookup, b -> bLookup|>]
(* Hold[If[a > 1, bLookup[23], aLookup[24]]] *)
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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