Why doesn't RuleDelayed hold Unevaluated?

前端 未结 3 1703
庸人自扰
庸人自扰 2020-12-30 11:31

The Mathematica\'s evaluator generally holds (or restores?) Heads Unevaluated of expressions supplied as arguments for Symbol

3条回答
  •  星月不相逢
    2020-12-30 12:27

    Reproducing the behavior of RuleDelayed with user-defined function "rd"

    Here is straightforward way to reproduce RuleDelayed evaluation behavior based on Sasha's description:

    <...> [Rule] expression undergoes validation, and once validated, it is stamped with a certain valid flag. Setting the valid flag initiates reevaluation sequence. This is happening until expression no longer changes.

    ClearAll[rd];
    SetAttributes[rd, {HoldRest, SequenceHold}];
    Options[rd] = {"Validated" -> None};
    expr : rd[args__] /; ("Validated" /. Options[Unevaluated[rd]]) =!= 
       Hold[expr] := (Options[
        Unevaluated[rd]] = {"Validated" -> Hold[expr]}; rd[args])
    
    In[6]:= rd[Unevaluated@Unevaluated[1 + 1], 
     Unevaluated@Unevaluated[Unevaluated[1 + 1]]]
    
    Out[6]= rd[2, 1 + 1]
    

    We can compare the number of evaluations of the first argument for rd and RuleDelayed:

    dummyFunction /; (++numberOfEvaluations; False) := Null;
    
    In[36]:= numberOfEvaluations=0;
    rd[dummyFunction,Unevaluated@Unevaluated[Unevaluated[1+1]]];
    numberOfEvaluations
    numberOfEvaluations=0;
    RuleDelayed[dummyFunction,Unevaluated@Unevaluated[Unevaluated[1+1]]];
    numberOfEvaluations
    Out[38]= 4
    Out[41]= 4
    

    Tracing rd and RuleDelayed

    The following demonstrates that this version replicates the behavior of RuleDelayed almost exactly. The only difference is the last additional evaluation of the final expression rd[2,1+1] which involves condition check and gives no match. With using rd as the second argument of Trace this last evaluation is excluded automatically. In the case of RuleDelayed this last check cannot be caught by Trace since it does not go through the evaluator.

    The code:

    ClearAll[rd];
    SetAttributes[rd, {HoldRest, SequenceHold}];
    SetAttributes[returnLast, {HoldRest}]
    SetAttributes[{NotValidatedQ, setValidatedFlag}, HoldAllComplete];
    Options[rd] = {"Validated" -> None};
    NotValidatedQ[expr_] := ("Validated" /. Options[Unevaluated[rd]]) =!= 
       Hold[expr];
    setValidatedFlag[expr_] := 
      Options[Unevaluated[rd]] = {"Validated" -> Hold[expr]};
    returnLast[first_, last_] := last;
    expr : rd[args__] /; NotValidatedQ[expr] := 
     returnLast[setValidatedFlag[expr], rd[args]]
    

    Comparison:

    rdList = DeleteCases[
       Trace[rd[Unevaluated@Unevaluated[1 + 1], 
         Unevaluated@Unevaluated[Unevaluated[1 + 1]]], 
        TraceOriginal -> 
         True], ({HoldForm[(validatedQ | setValidatedFlag)[_]], ___} | 
         HoldForm[_returnLast] | {HoldForm[returnLast]})] /. 
      rd -> RuleDelayed
    
    RuleDelayedList = 
     Trace[RuleDelayed[Unevaluated@Unevaluated[1 + 1], 
       Unevaluated@Unevaluated[Unevaluated[1 + 1]]], 
      TraceOriginal -> True]
    

    screenshot

    Tracing with using of the second argument of Trace shows exact match:

    In[52]:= rdList = 
      Trace[rd[Unevaluated@Unevaluated[1 + 1], 
         Unevaluated@Unevaluated[Unevaluated[1 + 1]]], rd, 
        TraceOriginal -> True] /. {HoldForm[_returnLast] -> Sequence[], 
        rd -> RuleDelayed};
    RuleDelayedList = 
      Trace[RuleDelayed[Unevaluated@Unevaluated[1 + 1], 
        Unevaluated@Unevaluated[Unevaluated[1 + 1]]], RuleDelayed, 
       TraceOriginal -> True];
    
    rdList === RuleDelayedList
    
    Out[54]= True
    

提交回复
热议问题