【问题标题】:Is it possible to create MakeBoxesStop wrapper?是否可以创建 MakeBoxesStop 包装器?
【发布时间】:2011-06-30 11:33:59
【问题描述】:

输出表达式通过MakeBoxes传递is known,将图形表达式转换为前端用来表示图形的框语言(当$Output具有默认选项FormatType->StandardForm时)。例如,如果我们评估:

HoldComplete[Graphics[Disk[]]]

我们得到一个由HoldComplete包裹的磁盘:

这是因为HoldComplete 不会阻止MakeBoxes 将其内容转换为排版表达式:

In[4]:= MakeBoxes@HoldComplete[Graphics[Disk[]]]
Out[4]= RowBox[{"HoldComplete", "[", GraphicsBox[DiskBox[{0, 0}]], "]"}]

所以我的问题是:是否可以对MakeBoxes 进行一些额外的定义,这样使用头部MakeBoxesStop 包装任何表达式将阻止MakeBoxes 将此表达式转换为排版形式?在这种情况下,表达式在输出中应该与任何其他表达式一样,其中没有与符号关联的规则;在上述情况下:

附:请不要建议使用InputForm,因为I am not satisfied with its default behavior。

【问题讨论】:

  • 正如我在过去的对话中多次提到的,HoldComplete 不会阻止 MakeBoxes... 这句话令人困惑。 HoldComplete 在评估阶段很重要,出于渲染(转换为框)的目的,它只是一个普通的包装器。我完全不明白你为什么在这里提到它。渲染/FE 重要的是表达式的结果框形式,这与内核中发生的评估完全不同。
  • @Leonnid @Alexey - 关于“在 FE 中渲染与内核中发生的事情”的评论让我想起了 this 对 John Fultz 的 MathGroup 帖子的回复。强制旧版图形渲染有帮助吗? (可能是一个愚蠢的建议,但我想我会分享)
  • @telefunkenvf14 我问错人了。但是 IMO 将盒子形式的表达式发送到 FE,即使它是图形也比发送图像更干净,所以除非真的有必要,否则我不会强制使用遗留图形渲染。

标签: wolfram-mathematica mathematica-frontend


【解决方案1】:

这个函数似乎可以做到:

Clear[MakeBoxesStop];
MakeBoxesStop /: MakeBoxes[MakeBoxesStop[expr_], form_] :=
  Module[{heldHeads = 
     Join @@ Cases[expr,s_Symbol[___] :> HoldComplete[s], {0, Infinity}, 
      Heads -> True], 
    modified, direct,  tempContext = ToString[Unique[]] <> "`"},
   Block[{$ContextPath = $ContextPath, $Packages  = $Packages},
     BeginPackage[tempContext];
       modified = 
        Join @@ Map[
          Function[head,
             ToExpression[ToLowerCase[ToString[Unevaluated[head]]],InputForm, HoldComplete],     
             HoldAllComplete], 
          heldHeads];
     EndPackage[];
     With[{newexpr = 
       expr /. (List @@ Thread[HoldPattern /@ heldHeads -> modified, HoldComplete])},
       With[{result = 
        MakeBoxes[newexpr, form] /. 
           Thread[Rule @@ 
              Map[List @@ 
                 Map[Function[head, ToString[Unevaluated[head]], HoldAllComplete], #] &,
                 {modified , heldHeads}]]
            },
            Remove @@ Names[tempContext <> "*"];
            result]]]];

它不会赢得优雅的比赛,并且可能不是很干净,但它似乎可以满足您的要求:

In[270]:= MakeBoxesStop[Graphics[Disk[]]]

Out[270]= Graphics[Disk[List[0, 0]]]

如果您不希望 MakeBoxesStop 中的表达式求值,请在正文中添加适当的属性和 Unevaluated 包装器。

编辑

以下简单的制盒函数基于here发布的 Mathematica 解析器:

Clear[toBoxes];
toBoxes[expr_] :=
  First[parse[tokenize[ToString@FullForm[expr]]] //. {
    head_String[elem_] :>    RowBox[{head, "[", elem, "]"}], 
    head_String[elems___] :>  RowBox[{head, "[", RowBox[Riffle[{elems}, ","]], "]"}]}]

那么,我们需要:

Clear[MakeBoxesStopAlt];
MakeBoxesStopAlt /: MakeBoxes[MakeBoxesStopAlt[expr_], form_] :=  toBoxes[expr]

例如:

In[327]:= MakeBoxesStopAlt[Graphics[Disk[]]]

Out[327]= Graphics[Disk[List[0, 0]]]

【讨论】:

  • 我发布了第一个工作版本。我可以很好地想象它可以变得更短,并且并不总是需要在 HoldComplete 中包装东西(特别是对于生成的符号)。
  • @Leonid 似乎没有必要 ToLowerCase 所有符号:在另一个上下文中移动它们 is sufficient。我不知道 MakeBoxes 如何递归地应用于原始表达式的确切细节,但似乎这个过程是由 MakeBoxes 本身控制的,我觉得可以通过添加适当的头部来停止这个递归过程定义为MakeBoxes。
  • @Leonid 当然,此定义必须将表达式进一步转换为BoxForms,但与FormatValues 等符号无关,如Graphics 等。
  • @Alexey 你说得对ToLowerCase - 这是第一个版本的工件,它没有本地化新符号。至于你停止MakeBoxes 的策略 - 好吧,祝你好运。我只能说,因为你仍然需要它来处理你想要“停止”它的头部内部部分,所以我认为这个策略没有多大意义(除了它听起来很复杂并且依赖于 @ 的实现细节987654340@)。在这个解决方案中,我尝试在可能的最高级别上重用MakeBoxes。如果需要特定符号的列表,也可以使用我的代码来实现。
  • @Alexey 实际上我查看了您的代码,虽然将符号移动到另一个上下文对您有用,但除非我使用更长的名称,否则它对我不起作用,因为我不想放弃 @ 987654342@ 上下文。使用较长的名称实际上会带来与使用 ToLowerCase 相同的混乱,所以我认为我不在乎使用哪个名称。
猜你喜欢
  • 1970-01-01
  • 2017-02-04
  • 1970-01-01
  • 2010-09-15
  • 1970-01-01
  • 2011-02-27
  • 2019-12-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多