坚持任何论点

fay*_*sou 16 wolfram-mathematica

是否可以定义一个在给定位置保存参数的函数?

或者做一些像HoldLast这样的东西作为HoldFirst的对应物?

Leo*_*rin 15

据我所知,在没有HoldN属性的意义上,你不能直接这样做.但是,下面有一个解决方案,应该按照您的要求进行操作.


提出的解决方案

一种简单的方法是定义一个将完成主要工作的辅助函数,以及您的"main"函数(实际将被调用的函数)HoldAll,如下所示:

In[437]:= 
SetAttributes[f, HoldAll];
f[a_, b_, c_] :=
   faux[a, Unevaluated[b], c];
faux[a_, b_, c_] := Hold[a, b, c]

In[440]:= f[1^2, 2^2, 3^2]
Out[440]= Hold[1, 2^2, 9] 
Run Code Online (Sandbox Code Playgroud)

您不必将其暴露faux到顶层,Module[{faux}, your definitions]而是可以包裹每一个.


通过元编程实现自动化

此过程可以自动完成.这是一个简单的函数签名解析器,用于提取模式名称(注意 - 它确实简单化):

splitHeldSequence[Hold[seq___], f_: Hold] := List @@ Map[f, Hold[seq]];

getFunArguments[Verbatim[HoldPattern][Verbatim[Condition][f_[args___], test_]]] := 
     getFunArguments[HoldPattern[f[args]]];

getFunArguments[Verbatim[HoldPattern][f_[args___]]] := 
     FunArguments[FName[f], FArgs @@ splitHeldSequence[Hold[args]]];

(*This is a simplistic "parser".It may miss some less trivial cases*)

getArgumentNames[args__FArgs] := 
   args //. {
     Verbatim[Pattern][tag_, ___] :> tag, 
     Verbatim[Condition][z_, _] :> z, 
     Verbatim[PatternTest][z_, _] :> z
   };
Run Code Online (Sandbox Code Playgroud)

使用这个,我们可以编写以下自定义定义运算符:

ClearAll[defHoldN];
SetAttributes[defHoldN, HoldFirst];
defHoldN[SetDelayed[f_[args___], rhs_], n_Integer] :=
   Module[{faux},
      SetAttributes[f, HoldAll];
      With[{heldArgs = 
         MapAt[
            Unevaluated,
            Join @@ getArgumentNames[getFunArguments[HoldPattern[f[args]]][[2]]],
            n]
         },
        SetDelayed @@ Hold[f[args], faux @@ heldArgs];
        faux[args] := rhs]]
Run Code Online (Sandbox Code Playgroud)

这将分析您的原始定义,提取模式名称,包装感兴趣的参数Unevaluated,介绍本地faux,并进行两步定义 - 基本上我们手动执行的步骤.我们需要SetDelayed @@ ..欺骗变量重命名机制With,以便它不会重命名lhs上的模式变量示例:

In[462]:= 
ClearAll[ff];
defHoldN[ff[x_,y_,z_]:=Hold[x,y,z],2]

In[464]:= ?ff
Global`ff
Attributes[ff]={HoldAll}

ff[x_,y_,z_]:=faux$19106@@Hold[x,Unevaluated[y],z]

In[465]:= ff[1^2,2^2,3^2]
Out[465]= Hold[1,2^2,9]
Run Code Online (Sandbox Code Playgroud)

笔记

请注意,这很简单,可以概括为需要保存参数的位置列表.一般来说,你需要一个更好的模式解析器,但上面简单的解析器可能是一个好的开始.还要注意,这种结构会引起一些运行时开销,而且当你或者主要的Module辅助函数faux不会被垃圾收集时- 你可能需要为你引入一个特殊的析构函数生成的函数.有关此问题的替代方法,请参阅帖子中的帖子(我介绍该函数的帖子).ClearRemovedefHoldNmakeHoldN

  • 我想投两次,一次是解决方案,一次是模糊的变量名称faux(是f_auxiliary还是法国faux =假/假?);-) (4认同)
  • @Leonid,Sjoerd:感谢可能为时过早.他说他想投票两次.但他并没有说他投了票(这会是一场虚假投票吗?) (4认同)