如何在Manipulate控件的定义中使用宏内部的宏?

Nas*_*ser 1 wolfram-mathematica

我正在使用Leonid的宏方法(见这里)来帮助我管理控制变量的布局Manipulate.

但我发现从宏中,我无法使用其他地方定义的另一个宏.所以我想知道是否有办法在另一个宏中使用宏?

为了解释这个问题,我将首先使用一个级别的宏显示一个非常简单的Manipulate,然后我将通过尝试使用另一个宏中的宏来显示问题.

Manipulate[Text["ok"],

 Evaluate@With[{

    x = Function[{},  (*----> macro x *)
      TabView[{
        "x" -> "working on x"
        }], HoldAll
      ],

    y = Function[{}, (*----> macro y *)
      TabView[{
        "y" -> "working on y"
        }], HoldAll
      ]
    },(*WITH*)

   (* now use the above macros *)
   Grid[{
     {SetterBar[Dynamic[choice], {1, 2}]},
     {Dynamic[Which[choice == 1, x[], choice == 2, y[]] ]}
     }]

   ],
 {{choice, 1}, None},
 ContentSize -> 300

 ]
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

现在为复选框添加一个宏,然后尝试从上面的'x'宏中使用它:

操纵[文字[ "确定"],

 Evaluate@With[{

    checkBox = Function[{}, Checkbox[Dynamic[c]], HoldAll],

    x = Function[{},
      TabView[{
        "x" -> checkBox[] (*=====> DOES NOT WORK, did not bind *)
        }], HoldAll
      ],

    y = Function[{},
      TabView[{
        "y" -> "working on y"
        }], HoldAll
      ]
    },(*WITH*)

   Grid[{
     {SetterBar[Dynamic[choice], {1, 2}]},
     {Dynamic[Which[choice == 1, x[], choice == 2, y[]] ]}
     }]

   ],
 {{choice, 1}, None},
 {{c, True}, None},
 ContentSize -> 300

 ]
Run Code Online (Sandbox Code Playgroud)

我们认为它不起作用.'x'宏没有'看到'复选框宏.

在此输入图像描述

但是如果我直接在'x'宏中添加复选框的代码,它当然会起作用:

Manipulate[Text["ok"],

 Evaluate@With[{

    x = Function[{},
      TabView[{
        "x" -> Checkbox[Dynamic[c]]  (* add the definition directly *)
        }], HoldAll
      ],

    y = Function[{},
      TabView[{
        "y" -> "working on y"
        }], HoldAll
      ]
    },(*WITH*)

   Grid[{
     {SetterBar[Dynamic[choice], {1, 2}]},
     {Dynamic[Which[choice == 1, x[], choice == 2, y[]] ]}
     }]

   ],
 {{choice, 1}, None},
 {{c, True}, None},
 ContentSize -> 300

 ]
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

所以,问题是:是否可以在'x'宏内使用上面的复选框宏?

为了使它更容易,我不会将任何参数传递给宏.我只是使用一个宏作为一个较大的代码片段(控制变量定义)的"简写"名称,如上所示.

这只是为了让我更容易通过仅移动宏名称来布局UI,而不是移动宏定义的更大的代码片段.由于Manipulate没有GUI构建器,因此当需要管理大量控件时,此方法会有所帮助.

Leo*_*rin 7

这是因为With在这种情况下你需要嵌套.您不能在同一个声明列表中使用另一个变量的声明With.以下是您问题的简化版本:

In[3]:= With[{a=b,c=f[a]},g[c]]
Out[3]= g[f[a]]
Run Code Online (Sandbox Code Playgroud)

这就是你需要的:

In[5]:= 
With[{a=b},
  With[{c=f[a]},g[c]]]

Out[5]= g[f[b]]
Run Code Online (Sandbox Code Playgroud)

在你的情况下,checkBox发挥作用a,并x发挥作用c.

关于如何制作一个版本的主题With将允许这样的连续绑定,在Mathgroup上和SO处讨论过几次.这是我实现这种构建的:

ClearAll[LetL];
SetAttributes[LetL, HoldAll];
LetL /: Verbatim[SetDelayed][lhs_, rhs : HoldPattern[LetL[{__}, _]]] :=
   Block[{With}, Attributes[With] = {HoldAll};
     lhs := Evaluate[rhs]];
LetL[{}, expr_] := expr;
LetL[{head_}, expr_] := With[{head}, expr];
LetL[{head_, tail__}, expr_] := 
  Block[{With}, Attributes[With] = {HoldAll};
     With[{head}, Evaluate[LetL[{tail}, expr]]]];
Run Code Online (Sandbox Code Playgroud)

如果你愿意使用它,你需要做的是改变WithLetL你的代码.