Macros 在Mathematica中打印符号名称和值

Macros 在Mathematica中打印符号名称和值,macros,wolfram-mathematica,Macros,Wolfram Mathematica,我想创建一个函数My`Print[args\uu],它打印我传递给它的符号的名称及其值。问题在于,在将符号传递到My`Print之前,会对它们进行求值。因此,My`Print永远看不到符号名称 一个解决方案是用未赋值[]来包围我传递给我的`打印的每个参数,但这看起来很混乱。有没有一种方法可以定义宏,这样当我键入My`Print[args\uuuu]时,Mathematica内核会看到My`Print[Unevaluated/@args\uu]?您需要在函数上设置属性,使用SetAttribute

我想创建一个函数
My`Print[args\uu]
,它打印我传递给它的符号的名称及其值。问题在于,在将符号传递到
My`Print
之前,会对它们进行求值。因此,
My`Print
永远看不到符号名称


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

您需要在函数上设置属性,使用
SetAttribute[My`Print]

下面是一个可能的实现:

Clear[my`print]
SetAttributes[my`print, HoldAll]
my`print[args__] := 
 Scan[
  Function[x, Print[Unevaluated[x], " = ", x], {HoldAll}], 
  Hold[args]
 ]
我使用小写名称来避免与包中的内置或函数发生冲突

编辑:


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

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

SetAttributes[MyPrint, HoldAll];
MyPrint[var_] := 
  Module[
    {varname = ToString[Hold[var]]},
    Print[StringTake[varname, {6, StringLength[varname] - 1}], 
                " = ", Evaluate[var]]
  ]
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
*)

除其他回答外,还考虑了函数的下限、自值和增值:

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}

聚会迟到-可以使用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}

在我做这件事之前没有看到Szabolcs的代码。无论如何,我将把它留作另一个示例。除了
HoldAll
之外,Szabolcs'和您的方法几乎没有重叠。不需要借口,我会说,品种越多越好。非常清楚!但是
ToString
不是必需的-
Print[HoldForm[arg],“=”,arg]
就足够了。+1非常优雅,尽管{Null,Null,Null}输出很小blemish@Sjoerd实际上,我可以通过在extra
(…)中包装
prn[{args}]
来抑制输出,但这看起来很难看:)。你也可以在函数的末尾用分号来调用它,我也喜欢你如何使函数对多个参数有效。不过,它有一个缺点:试试
prn[{ape,nut,mouse},sheep]
。我知道这有点牵强,但它与将迭代器作为参数传递并没有什么不同;-)@是的,你是对的。但对我来说,这更多的是我函数中错误检查的缺陷,而不是核心方法的缺陷,因为这样的参数不应该被传递。我可以将模式从
args\uuuuuuuuu
更改为
args:(除了[\u列表]…)
,并可能排除您提到的麻烦案例(我没有检查)。两个注释。第一个是非常不明显的-查看以下代码:
i=0;我的`打印[i++]
。生成的错误消息令人费解,原因是
Do
使用动态范围(A-la
Block
)来定位其变量(
i
)。执行的代码碰巧修改了
i
,这只有在下一次循环迭代重置
i
之前才有效,但在这里这很重要。定义函数时,可以通过在
模块[{i},…]
中包装
SetDelayed
来避免这种情况。第二个注意事项:通过在
列表
中包装
参数
,可以对它们进行多次评估,如果它们的执行触发了…`,这可能是不可取的。。。副作用。例如,这里:
i=j=k=0;我的`打印[i++,j++,k++];{i,j,k}
,您得到输出
i++=1,j++=1,k++=3
,最后,所有
i,j,k
都设置为
4
。您可以通过始终使用
Hold[args]
@Leonid True来避免这种情况。我发现的第一个变量完全是偶然的,意外地将其中一个变量命名为
I
。我没有料到这一点(尽管回顾起来这是合乎逻辑的),我花了一段时间才理解。在任何情况下,没有人会减损你的答案,我投了更高的票。不过,从理论上讲,这证实了使用更短、更高级别的代码时,出现bug的机会也更少。
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}