【问题标题】:The clearest way to represent Mathematica's evaluation sequence表示 Mathematica 求值序列的最清晰方法
【发布时间】:2011-03-28 13:32:49
【问题描述】:

WReachhere 提供了一种使用OpenerView 表示Mathematica 评估序列的好方法。它比使用标准的TraceTracePrint 命令清晰。但它还可以进一步改进。

我需要直接的方式来表示 Mathematica 的初学者主循环中的(子)评估的真实序列。特别是,新的求值子序列何时开始以及从哪个表达式开始应该很明显(最好将每个子序列精确地放在一个Opener 中)。应使用the standard evaluation sequence 尽可能轻松地识别评估(子)序列。我的意思是读者应该能够将真正的评估步骤映射到the standard evaluation sequence 的文档中描述的步骤。

有可能吗?

【问题讨论】:

    标签: programming evaluation


    【解决方案1】:

    citedOpenerView 解决方案使用Trace / TraceOriginal 生成其内容。这允许在该响应中简洁地定义show 的定义,但具有丢弃一些跟踪信息的缺点。 TraceScan 提供更多信息,因为它在每次评估的开始和结束时调用用户指定的函数。

    下面定义了两个函数,它们尝试将TraceScan 信息格式化为(有点)可读的形式。

    traceView2 显示评估时的每个表达式,以及导致该评估结果的子评估(“步骤”)。 “向下钻取”由OpenerView 提供。该函数生成如下所示的输出:

    traceView2[(a + 1) + 2]
    

    随着视图的深入,它会迅速从页面的右侧爬出。 traceView4 提供了一种替代视图,该视图不显示爬行行为,但代价是为任何给定评估显示更少的上下文:

    选择你的毒药;)

    函数的定义如下...

    traceView2

    ClearAll@traceView2
    traceView2[expr_] :=
      Module[{steps = {}, stack = {}, pre, post, show, dynamic},
        pre[e_] := (stack = {steps, stack}; steps = {})
      ; post[e_, r_] :=
          ( steps = First@stack ~Join~ {show[e, HoldForm[r], steps]}
          ; stack = stack[[2]]
          )
      ; SetAttributes[post, HoldAllComplete]
      ; show[e_, r_, steps_] :=
          Grid[
            steps /. {
              {} -> {{"Expr  ", Row[{e, " ", Style["inert", {Italic, Small}]}]}}
            , _ -> { {"Expr  ", e}
                   , {"Steps", steps /.
                       { {} -> Style["no definitions apply", Italic]
                       , _ :> OpenerView[{Length@steps, dynamic@Column[steps]}]}
                     }
                   , {"Result", r}
                   }
            }
          , Alignment -> Left
          , Frame -> All
          , Background -> {{LightCyan}, None}
          ]
      ; TraceScan[pre, expr, ___, post]
      ; Deploy @ Pane[steps[[1]] /. dynamic -> Dynamic, ImageSize -> 10000]
      ]
    SetAttributes[traceView2, {HoldAllComplete}]
    

    traceView4

    ClearAll@traceView4
    traceView4[expr_] :=
      Module[{steps = {}, stack = {}, pre, post},
        pre[e_] := (stack = {steps, stack}; steps = {})
      ; post[e_, r_] :=
          ( steps = First@stack ~Join~ {{e, steps, HoldForm[r]}}
          ; stack = stack[[2]]
          )
      ; SetAttributes[post, HoldAllComplete]
      ; TraceScan[pre, expr, ___, post]
      ; DynamicModule[{focus, show, substep, enter, exit}
        , focus = steps
        ; substep[{e_, {}, _}, _] := {Null, e, Style["inert", {Italic, Small}]}
        ; substep[{e_, _, r_}, p_] :=
            { Button[Style["show", Small], enter[p]]
            , e
            , Style[Row[{"-> ", r}], Small]
            }
        ; enter[{p_}] := PrependTo[focus, focus[[1, 2, p]]]
        ; exit[] := focus = Drop[focus, 1]
        ; show[{e_, s_, r_}] :=
           Column[
             { Grid[
                 { {"Expression", Column@Reverse@focus[[All, 1]]}
                 , { Column[
                       { "Steps"
                       , focus /.
                           { {_} :> Sequence[]
                           , _ :> Button["Back", exit[], ImageSize -> Automatic]
                           }
                       }
                     ]
                   , Grid[MapIndexed[substep, s], Alignment -> Left]
                   }
                 , {"Result", Column@focus[[All, 3]]}
                 }
               , Alignment -> Left, Frame -> All, Background -> {{LightCyan}}
               ]
             }
           ]
        ; Dynamic @ show @ focus[[1]]
        ]
      ]
    SetAttributes[traceView4, {HoldAllComplete}]
    

    【讨论】:

    • 非常好!现在评估的顺序在视觉上非常清晰! Trace* 命令完全松散的一件事是应用Orderless 属性。在应用Orderless 属性后,我很惊讶地发现Plus[a, 1] 确实以Plus[1, a] 的形式再次评估!这似乎与the standard evaluation sequence 的描述相矛盾。
    • 漂亮。现在为 XML 编写类似的代码...(如果您无事可做):) +1.
    • 您能否解释一下为什么只在traceView2 的末尾应用Dynamic,将每个dynamic 替换为Dynamic?出于性能原因?
    • @IstvánZachar dynamic 替换是不必要的——它是该函数先前版本的剩余代码。它甚至可以被认为是有害的,因为最好推迟内部OpenerViews 的创建。我会修复它,但我注意到这些函数现在在我编写此响应后发布的 Mathematica 版本中的复杂跟踪性能非常差。似乎一些相关的性能特征在后来的 V7 微修订版(可能是 V7.0.1)中发生了变化。这些功能需要重新审视(但我现在不能这样做)。
    • 为什么不把这段代码放到 GitHub 上呢?现在人们可能会从这里复制此代码,并对其进行修改以供个人使用。但是为了整个社区的利益,这些改进永远不会回到这里。 GitHub 将鼓励人们将更改贡献回来,或者至少会更容易追踪修改后的版本。为什么选择 GitHub 而不是其他网站?因为 GitHub 允许人们在浏览器中编辑源代码,甚至不需要安装 git。这实际上可以与这样的短函数一起使用。
    【解决方案2】:

    只是对 WReach 非常有用的 traceView 功能的更新:更紧凑的视图,用于打开/折叠层次结构的更大按钮,以及保存按钮状态。

    ClearAll[traceViewCompact];
    SetAttributes[traceViewCompact, {HoldAllComplete}];
    traceViewCompact[expr_] := 
      Module[{steps = {}, stack = {}, pre, post, show, default = False},
       pre[e_] := (stack = {steps, stack}; steps = {});
       post[e_, 
         r_] := (steps = First@stack~Join~{show[e, HoldForm@r, steps]}; 
         stack = stack[[2]]);
       SetAttributes[post, HoldAllComplete]; 
       show[e_, r_, steps_] := Module[{open = False},
         Grid[
          steps /. {{} -> {{"Expr  ", 
               Item[e, Background -> GrayLevel@.8]}}, _ -> {{"Expr  ", 
               e}, {Toggler[
                Dynamic@
                 open, {True -> 
                  Button["Steps", Appearance -> {"DialogBox", "Pressed"}],
                  False -> Button@"Steps"}], 
               steps /. {{} -> Style["no definitions apply", Italic], _ :>
                   Dynamic@
                   If[open, Column@steps, 
                    Grid@{{Length@steps, "steps"}}]}}, {"Result", r}}}, 
          Alignment -> {Left, Center}, Frame -> All, 
          Spacings -> Automatic, Background -> {{Hue[.65, .1, 1]}, None}]
         ];
       TraceScan[pre, expr, ___, post];
       Deploy@Column@{
          Opener@Dynamic@default,
          Dynamic@Pane[First@steps, ImageSize -> 10000]
          }];
    
    
    traceViewCompact[(a + 1) + 2]
    

    【讨论】:

    • 在 v10.3 中,它很容易被冻结和分解 mma。可以尝试追踪这个函数mathematica.stackexchange.com/a/80173/4742
    • 说实话,我从来没有真正使用过这些示踪剂,甚至我的也没有。 WReach(上图)的原始 traceView 在 v10.3 中是否可以正常工作?如果是这样,我建议使用它,因为我很遗憾没有时间调试调试器。可能是一个非常递归的问题:)
    • 好的,我明白了。 WReach 的功能在 10.3 中运行良好
    【解决方案3】:

    这是我的方法,也是基于 WReach 的 OpenerView 技术。它的布局比他的 traceView2 紧凑得多,虽然不那么明确,而且据我所知,唯一牺牲的信息是显示隐藏在每个 OpenerView 中的步数。评估未更改的表达式由禁用的 OpenerView 指示,尽管我制作的屏幕截图没有显示禁用和启用的 OpenerView 之间的区别。

    SetAttributes[TraceView, HoldFirst]

    TraceView[e_, s___, opts : OptionsPattern[Trace]] := 
     Module[{show2},
      show2[{expr_, steps__}] := 
      OpenerView[{expr, Column[show2 /@ {steps}]}]; 
      show2[{HoldForm[x_]}] := Row[{Opener[True, Enabled -> False], HoldForm[x]}]; 
      show2[HoldForm[x_]] := HoldForm[x];
      show2[Trace[Unevaluated[e], s, opts, TraceOriginal -> True]]
     ]
    

    【讨论】:

    • 有趣的是,TraceScanTraceTraceOriginal -> True 的输出略有不同。在第二种情况下,(a+1) 的评估链在步骤“1+a”之前显示了附加步骤“a+1”。我不明白这个额外的步骤代表什么。有人有什么想法吗?
    • 我已经在separate thread回答了这个问题。
    【解决方案4】:

    这是 joebolte 的 TraceView 的另一个实现,使用 12.3 中的新 Tree 功能:

    SetAttributes[TraceView, HoldFirst];
    TraceView[expr_] := Module[{trace, f, h, tree},
      trace = Trace[expr, TraceOriginal -> True];
      f[steps_List] := Rest[steps];
      f[step_] := {};
      h[steps_List] := First[steps];
      h[step_] := step;
      tree = NestTree[f, trace, Infinity, h];
      TreeOutline[tree]]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-08-14
      • 2012-04-03
      • 1970-01-01
      • 2013-03-24
      • 1970-01-01
      • 2021-07-18
      • 2019-12-24
      相关资源
      最近更新 更多