【问题标题】:Printing symbol name and value in Mathematica在 Mathematica 中打印符号名称和值
【发布时间】:2011-11-02 17:57:16
【问题描述】:

我想创建一个函数My`Print[args__] 来打印我传递给它的符号的名称以及它们的值。问题在于,在将符号传递给 My`Print 之前,会对它们进行评估。所以My`Print 永远看不到符号名称。

一种解决方案是用Unevaluated[] 包围我传递给My`Print 的每个参数,但这看起来很混乱。有没有一种方法可以定义宏,当我输入 My`Print[args__] 时,Mathematica 内核会看到 My`Print[Unevaluated /@ args__]

【问题讨论】:

    标签: macros wolfram-mathematica


    【解决方案1】:

    您需要在您的函数上设置属性HoldAll,使用SetAttribute[my`print]

    这是一个可能的实现:

    Clear[my`print]
    SetAttributes[my`print, HoldAll]
    my`print[args__] := 
     Scan[
      Function[x, Print[Unevaluated[x], " = ", x], {HoldAll}], 
      Hold[args]
     ]
    

    我使用小写名称来避免与包中的内置函数或函数发生冲突。

    编辑:

    明确地说:我在这里有两个功能。将打印 single 符号的值,并在内部实现为 Function。如果足够,您可以单独使用它。另一个是实际的my`print 函数。请注意,两者都需要具有HoldAll 属性。

    【讨论】:

      【解决方案2】:
      ClearAll[My`Print]
      SetAttributes[My`Print, HoldAll]
      My`Print[args___] := 
       Do[
         Print[
            Extract[Hold[args], i, HoldForm], "=", List[args][[i]]
         ], {i, Length[List[args]]}
       ]
      
      ape = 20;
      nut := 20 ape;
      mouse = cat + nut;
      
      My`Print[ape, nut, mouse]
      
      (* ==>
      ape=20
      nut=400
      mouse=400+cat
      *)
      

      【讨论】:

      • 两个音符。第一个非常不明显 - 查看此代码:i = 0;My`Print[i++]。生成的错误消息令人费解,这是由于Do 使用动态作用域(a-la Block)来本地化其变量(此处为i)。执行的代码碰巧修改了i,它只有在下一次循环迭代重置i 时才会生效——但这很重要。您可以通过在定义函数时将SetDelayed 包装在Module[{i},...] 中来避免这种情况。第二个注意事项:通过将args 包装在List 中,您可以多次评估它们,如果它们的执行触发... `
      • ... 副作用。例如,在这里:i = j = k = 0;My`Print[i++, j++, k++];{i, j, k},您会得到输出i++=1, j++ = 1, k++ = 3,最后,所有i,j,k 都设置为4。您可以通过始终使用Hold[args] 来避免这种情况。
      • @Leonid True,应该多考虑一下。
      • 我偶然发现的第一个变量,不小心将其中一个变量命名为i。我没想到这一点(尽管回想起来是合乎逻辑的),我花了一段时间才理解。无论如何,没有人会减损你的回答,我赞成。不过,从哲学​​上讲,这证实了使用更短和更高级别的代码,我们出现错误的机会也更少。
      【解决方案3】:
      SetAttributes[MyPrint, HoldAll];
      MyPrint[var_] := 
        Module[
          {varname = ToString[Hold[var]]},
          Print[StringTake[varname, {6, StringLength[varname] - 1}], 
                      " = ", Evaluate[var]]
        ]
      

      【讨论】:

      • 在我这样做之前没有看到 Szabolcs 的代码。无论如何,我会把它作为另一个示例。
      • 除了HoldAll 之外,Szabolcs 和您的方法之间几乎没有重叠。不用找借口了,品种越多越好。
      【解决方案4】:

      迟到 - 可以使用 Listability 获得一个相当优雅 (IMO) 的解决方案,避免显式循环或评估控制结构:

      ClearAll[prn];
      SetAttributes[prn, {HoldAll, Listable}];
      prn[arg_] := Print[HoldForm[arg], " = ", arg];
      prn[args___] := prn[{args}]
      

      从@Sjoerd 窃取测试用例,

      In[21]:= prn[ape,nut,mouse]
      
      During evaluation of In[21]:= ape = 20
      During evaluation of In[21]:= nut = 400
      During evaluation of In[21]:= mouse = 400+cat
      
      Out[21]= {Null,Null,Null}
      

      【讨论】:

      • +1。非常清楚!但是ToString 不是必需的 - Print[HoldForm[arg], " = ", arg] 就足够了。
      • +1 非常优雅,虽然 {Null,Null,Null} 输出是一个小瑕疵
      • @Sjoerd 事实上,我可以通过将prn[{args}] 包裹在额外的(...); 中来抑制输出,但这看起来很难看:)。作为一种替代方法,可以在末尾使用分号调用该函数。
      • 我也喜欢你如何使函数有效地与多个参数一起使用。不过它有一个缺点:试试prn[{ape, nut, mouse}, sheep]。我知道这有点牵强,但这与将迭代器作为参数传递并没有什么不同;-)
      • @Sjoerd 是的,你是对的。但对我来说,这更多是我的函数中错误检查的缺陷,而不是核心方法的缺陷,因为不应该传递这样的参数。我可以将模式从args___ 更改为args:(Except[_List]...),并且大概排除您提到的麻烦情况(我没有检查)。
      【解决方案5】:

      这是My`Print 的另一个变体,可以添加到组合中:

      ClearAll[My`Print]
      SetAttributes[My`Print, HoldAll]
      My`Print[expr_] := Print[HoldForm[expr], " = ", expr]
      My`Print[exprs___] := Scan[My`Print, Hold[exprs]]
      

      ...还有另一个...

      ClearAll[My`Print]
      SetAttributes[My`Print, HoldAll]
      My`Print[args___] :=
        Replace[
          Unevaluated @ CompoundExpression @ args
        , a_ :> Print[HoldForm[a], " = ", a]
        , {1}
        ]
      

      不管怎样,用法都是一样的:

      $x = 23;
      f[x_] := 1 + x
      
      My`Print[$x, $x + 1, f[1]]
      
      (* prints:
         $x = 23
         $x+1 = 24
         f[1] = 2
      *)
      

      【讨论】:

        【解决方案6】:

        除了其他答案,请考虑函数 DownValues、OwnValues 和 UpValues:

        In[1] := f[x_] := x^2
        
        In[2] := f[x_, y_] := (x + y)^2
        
        In[3] := DownValues[f]
        
        Out[3] = {HoldPattern[f[x_]] :> x^2, HoldPattern[f[x_, y_]] :> (x + y)^2}
        

        http://reference.wolfram.com/mathematica/ref/DownValues.html

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-11-22
          • 1970-01-01
          • 2010-11-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-12-20
          相关资源
          最近更新 更多