用Mathematica进行咖喱处理

| 使用以下构造,可以在Mathematica中实现有限形式的Currying:
f[a_][b_][c_] := (a^2 + b^2)/c^2
允许这样做,例如:
f[4][3] /@ Range@5
  {25,25/4,25/9,25/16,1} 有一个问题:“ 2”仅适用于第一个(一组)自变量。考虑:
ClearAll[f]
SetAttributes[f, HoldAllComplete]

f[a_][b_][c_] :=
  {ToString@Unevaluated@a,
   ToString@Unevaluated@b,
   ToString@Unevaluated@c}

f[2 + 2][ 8/4 ][3 + 5]
   {\“ 2 + 2 \”,\“ 2 \”,\“ 8 \”} 我的意图是返回列表中的
\"8 / 4\"
\"3 + 5\"
。 所以: 有没有办法将属性扩展到此构造? 是否有另一个方便的构造来实现这一目标? 除了属性以外,还有其他方法可以在Mathematica中扩展Currying吗?     
已邀请:
抱歉,可能没有相关评论。我刚刚搜索了“使用Mathematica进行搜索”,这个问题是Google列表中的第一个。虽然已经1岁了,但是已经得到了答案,但是我发现提出的解决方案并不是很优雅。初始代码的简单修改如下:
ClearAll[f]
SetAttributes[f, HoldAllComplete]
f[a_, b_, c_] := {ToString@Unevaluated@a, ToString@Unevaluated@b,
ToString@Unevaluated@c}
f[a__] := Function[x, f[a, x], HoldAll]
它导致所需的携带:
f[2+2][2+1] /@ Unevaluated@{1+1, 3+3}
{{2+2, 2+1, 1+1}, {2+2, 2+1, 3+3}}
它适用于三个可能的参数分区
f[1 + 1, 2 + 2, 6 + 1]
f[1 + 1, 2 + 2][6 + 1]
f[1 + 1][2 + 2][6 + 1]
并给出正确的结果:
{\"1+1\", \"2+2\", \"6+1\"}}
,但for11ѭ失败。对于这个,可以使用一些高级版本:
ClearAll[f, g]
SetAttributes[f, HoldAllComplete]
SetAttributes[g, HoldAllComplete]
f[a_, b_, c_] := (ClearAll[g]; SetAttributes[g, HoldAllComplete]; 
  Thread[Hold[{a, b, c}]] /. {Hold[e_] :> ToString@Unevaluated[e]})
f[a__] := (g[x__] := f[a, x]; g)
    
我认为没有任何方法可以将属性应用于此类“ upvalue \”模式定义的后面。 一种替代方法是使用带有属性的纯函数。不像模式匹配那样方便,但是当您评估
f[2+2][8/4]
时,它实际上提供了Curry想要的结果。 (如果您熟悉lambda演算,则“ Function”是Mathematica的“ lambda”。)
f = Function[a,Function[b,Function[c,HoldForm@{a,b,c},HoldAll],HoldAll],HoldAll]
我认为您希望能够执行以下操作:
f[2+2][2/1] /@ Unevaluated@{1+1,3+3}
{{2+2, 2/1, 1+1}, {2+2, 2/1, 3+3}}
如果您经常要执行这种操作,则可以使键入以下内容变得更加容易:
hf[args_,body_]:=Function[args,body,HoldAll]; SetAttributes[hf,HoldAll];
f = hf[a, hf[b, hf[c, HoldForm@{a, b, c}]]]
Mathematica Cookbook在第73-77页上提出了一种截然不同的Currying方法。 作为一般准则,如果您尝试控制Mathematica何时计算表达式,将使自己感到痛苦。在许多情况下,更好的方法是将符号用作您尚不想评估的表达式的占位符,然后当需要评估一个表达式时,可以将所需的表达式替换为符号。     
我不知道有什么方法可以将属性扩展到第二个或以后的咖喱参数列表中,尽管我很想听听一个。 您可以使用纯函数来实现与咖喱表达式具有相同外观的表达式定义(尽管我会毫不犹豫地称其为“便捷”):
ClearAll[f, f1, f2]
SetAttributes[{f, f1, f2}, HoldAllComplete]
f[a_] := Function[b, f1[a, b], HoldAllComplete]
f1[a_, b_] := Function[c, f2[a, b, c], HoldAllComplete]
f2[a_, b_, c_] :=
  { ToString@Unevaluated@a
  , ToString@Unevaluated@b
  , ToString@Unevaluated@c
  }

f[2+2][8/4][3+5]
可以使用现在未记录的符号
HeadCompose
对匹配的表达式进行模式匹配:
In[65]:= MatchQ[g[x][y][z], HeadCompose[g, x_, y_, z_]]
Out[65]= True
...尽管此功能无法解决当前问题。
HeadCompose
已在多个版本中弃用,以至于最终将其从文档中删除。但是我不知道有什么其他方式可以匹配咖喱表达式。我推测它之所以被弃用,恰恰是因为它不能有效地附加属性和定义,使它处于可怕的状态:该符号尚未完全集成到Mathematica的长期系统中,并且可能会发生变化。     
来晚了-不能直接回答问题(其他职位对此回答得很好)。我只想指出,通过使用“ 23”和异常,可以对评估进行某种形式的非本地控制。这有点丑陋,但是我认为它没有被充分探索。这是一个例子:
ClearAll[f];
f := With[{stack = Stack[_]},
   With[{fcallArgs = 
      Cases[stack, HoldForm[f[x_][y_][z_]] :> Hold[x, y, z]]},
      Throw[First@fcallArgs] /; fcallArgs =!= {}]];


In[88]:= Catch[f[2+2][8/4][3+5]]

Out[88]= Hold[2+2,8/4,3+5]
这利用了以下事实:在元素之前对头进行递归评估。从这里您可以看到,人们能够以这种方式提取未评估的参数,并且也许可以将其用于进一步处理。但是,计算被中断。还应该有可能从ѭ25中提取足够的信息以恢复计算。我不确定是否可以在Mathematica中实现延续,但是如果可以,那么可能应该遵循这些原则。     
有一种方法可以自动执行。考虑功能
f[a_, b_, c_] := {a, b, c}
为此,我们要使其隐式为“ curryable”,因此可以通过以下任何一种方式调用它:
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:= Funcion [a,Function [b,Function [c,BODY]]],但是那样我们将不能通过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
更新,现在属性(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]}
    

要回复问题请先登录注册