Wolfram mathematica 如何在定义操纵控件时从宏内部使用宏?

Wolfram mathematica 如何在定义操纵控件时从宏内部使用宏?,wolfram-mathematica,Wolfram Mathematica,我正在使用Leonid的宏方法()来帮助我管理操作的控制变量布局 但我发现,在宏中,我无法使用其他地方定义的另一个宏。所以我想知道是否有一种方法可以从另一个宏中使用一个宏 为了解释这个问题,我将首先展示一个使用一级宏的非常简单的操作,然后通过尝试从另一级宏中使用宏来展示问题 Manipulate[Text["ok"], Evaluate@With[{ x = Function[{}, (*----> macro x *) TabView[{ "x

我正在使用Leonid的宏方法()来帮助我管理
操作的控制变量布局

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

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

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

 ]

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

操纵[文本[“确定”]

我们看到它不起作用。“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

 ]

因此,问题是:是否可以从“x”宏内部使用上面的复选框宏

为了更简单,我没有向宏传递任何参数。我只是使用宏作为较大代码片段(控制变量定义)的“速记”名称,如上所示


这只是为了让我更容易通过只移动宏名称来布局UI,而不是移动宏定义的较大的代码段。因为没有用于操纵的GUI生成器,所以当有许多控件要管理时,这种方法会有所帮助。

这是因为在这种情况下,您需要一个带有
的嵌套
。您可以在
的同一声明列表中,不要将一个变量的声明用于另一个变量。以下是问题的简化版本:

In[3]:= With[{a=b,c=f[a]},g[c]]
Out[3]= g[f[a]]
这正是您需要的:

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

Out[5]= g[f[b]]
在您的情况下,
复选框
扮演
a
的角色,
x
扮演
c
的角色

关于如何使用
制作一个版本的
,以允许这种连续绑定的主题,在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]]]];

如果你愿意使用它,你所要做的就是在你的代码中将
With
更改为
LetL

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

In[3]:= With[{a=b,c=f[a]},g[c]]
Out[3]= g[f[a]]
这正是您需要的:

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

Out[5]= g[f[b]]
在您的情况下,
复选框
扮演
a
的角色,
x
扮演
c
的角色

关于如何使用制作一个版本的,以允许这种连续绑定的主题,在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]]]];

如果你愿意使用它,你所要做的就是在你的代码中将
With
更改为
LetL

我是这个网站的新手,所以你尝试做的事情可能有不同的目标,但你有没有理由不能直接编写代码

DynamicModule[{choice = 1, c = False},

 Grid[{
   {SetterBar[Dynamic[choice], {1, 2}]},
   {Dynamic[
     Which[choice == 1, TabView[{"x" -> Checkbox[Dynamic[c]]}], 
      choice == 2, TabView[{"y" -> "working on y"}]]]},
   {Dynamic[choice], Dynamic[c]}
   }]
 ]

我是这个网站的新手,所以你尝试做的事情可能有不同的目标,但是有什么原因不能直接编写代码呢

DynamicModule[{choice = 1, c = False},

 Grid[{
   {SetterBar[Dynamic[choice], {1, 2}]},
   {Dynamic[
     Which[choice == 1, TabView[{"x" -> Checkbox[Dynamic[c]]}], 
      choice == 2, TabView[{"y" -> "working on y"}]]]},
   {Dynamic[choice], Dynamic[c]}
   }]
 ]

重点是,更大/更复杂的动态接口往往包含大量类型的代码重复,这不容易排除,因为,特别是通过常规方法,我们可能会将一些动态符号带出范围。你可以看看这篇文章:,其中给出了这样的示例。我在那里倡导的方法是基于在运行时代码生成上,因此生成的
操作
与手写的完全相同。这个新的…问题是该讨论的逻辑延续,处理希望使用嵌套宏的情况。OP给出了他认为可以说明该问题的最小示例(这是一件非常正确的事情),这可能就是为什么这个问题让你感到困惑的原因。在更大的动态接口环境中,它会变得更有意义。作为一个如何做这件事或那件事的练习,这是很公平的,但如果构建复杂的接口是一个目标,那么对于初学者来说,我不知道为什么会使用操纵。换句话说,像这样的需要是可能的y由于操纵的刚性。使用DynamicModule,这些问题将在很大程度上消失。@MikeHoneychurch,要发布WRI网站的演示,不允许直接使用Dynamics构建它,但必须使用操纵[]。即,演示CDF必须都在操纵[]内.嗨,纳赛尔,是的,我知道,所以如果在演示网站上发布是你的目标,那么不言而喻,你必须使用操纵。问题中没有说明这一目标,所以我是回应Leonid提到的“更大的动态界面”Wolfram自己的更大的动态接口,例如其CDF示例,不使用Operate。问题是,更大/更复杂的动态接口往往包含大量类型的代码重复,这不容易排除,因为,特别是通过常规方法,我们可能会将一些动态符号带出范围。您可以查看这篇文章:,这里有这样的例子。我提倡的方法是基于运行时代码生成的,因此产生的
操作
与手写的完全相同。这个新的…问题是该讨论的逻辑延续,处理希望使用嵌套宏的情况。OP介绍了在会议上,他考虑了一个简单的例子来说明这个问题(在国际海事组织,这是一件非常正确的事情),这可能就是为什么这个问题让你感到困惑的原因。在更大的动态接口环境中,它会变得更有意义。作为一个如何做这件事或那件事的练习,这是很公平的,但如果构建复杂的接口是一个目标,那么对于初学者来说,我不知道为什么会使用操纵。换句话说,像这样的需要是可能的由于刚度的原因