有一种方法可以自动完成。考虑函数
f[a_, b_, c_] := {a, b, c}
我们想让它隐式地“可咖喱”,所以它可以用以下任何一种方式调用:
f[1, 2, 3]
f[1, 2][3]
f[1][2][3]
如果有一种方法可以自动生成以下定义(我们在下面进行),则可以实现这一点:
f[a_, b_, c_] := {a, b, c}
f[a_, b_] := Function[c, f[a, b, c]]
f[a_] := Function[b, Function[c, f[a, b, c]]]
正如 Matt 上面的另一个答案,我们可以只做一个定义:f:=Function[a,Function[b,Function[c, BODY]]],但是我们将无法通过 f[ 调用 f a,b,c] 或 f[a,b],并且只能将其称为 f[a][b] 或 f[a][b][c]。有了多个定义,我们可以选择任何一种样式。
生成这些定义可以通过函数(定义如下)CurryableSetDelayed 完成,只需调用:
CurryableSetDelayed[f[a_, b_, c_], {a, b, c}]
即使定义了这些符号中的任何一个,这也将按预期工作,就像 SetDelayed 一样。
此外,使用 Notation 包,您可以使其显示为赋值运算符;说 f[a_,b_,c]#={c,b,a},但我没有尝试。
在下面的源代码中,我使用了一些可能与会话冲突的临时符号,因此如果您要使用它,请将其包含在包命名空间中。
完整代码:
ClearAll[UnPattern];
ClearAll[MakeFunction]
ClearAll[CurriedDefinitions]
ClearAll[MyHold]
ClearAll[MyHold2]
ClearAll[CurryableSetDelayed]
SetAttributes[UnPattern,HoldAllComplete];
SetAttributes[MakeFunction,HoldAllComplete];
SetAttributes[CurriedDefinitions,HoldAllComplete]
SetAttributes[MyHold,HoldAllComplete]
SetAttributes[MyHold2,HoldAllComplete]
SetAttributes[CurryableSetDelayed,HoldAllComplete]
UnPattern[x_]:=Block[{pattern},MyHold[x]/. Pattern->pattern/. pattern[v_,_]:>v]
MakeFunction[param_,body_,attrs_]:=With[{p=UnPattern[param],b=UnPattern[body]},
Block[{function},MyHold[function[p,b,attrs]]/. function->Function]]
CurriedDefinitions[fname_[args__],body_,attrs_]:=MapThread[MyHold2[#1:=#2]&,
{Rest[(MyHold[fname]@@#1&)/@NestList[Drop[#1,-1]&,{args},Length[{args}]-1]],
Rest[FoldList[MakeFunction[#2,MyHold[#1],Evaluate[attrs]]&,MyHold[fname[args]],
Reverse[Drop[{args},1]]]]}]
CurryableSetDelayed[fname_[args__],body_]:={MyHold2[fname[args]:=body],
Sequence@@CurriedDefinitions[fname[args],body,Attributes[fname]]}
//. MyHold[x_]:>x/. MyHold2[x_]:>x
更新,现在 Attributes (HoldAllComplete 等) 扩展到所有参数,所以以下工作按预期工作,只要您在调用 CurryableSetDelayed之前设置属性:
In[1185]:= ClearAll[f];
SetAttributes[f, {HoldAllComplete}]
CurryableSetDelayed[
f[a_, b_, c_], {ToString@Unevaluated@a, ToString@Unevaluated@b,
Unevaluated@c, Hold@c}];
f[1 + 1, 2 + 2, c + 1]
f[1 + 1, 2 + 2][c + 1]
f[1 + 1][2 + 2][c + 1]
Out[1188]= {"1 + 1", "2 + 2", Unevaluated[c + 1], Hold[c + 1]}
Out[1189]= {"1 + 1", "2 + 2", Unevaluated[c + 1], Hold[c + 1]}
Out[1190]= {"1 + 1", "2 + 2", Unevaluated[c + 1], Hold[c + 1]}