用Mathematica卷曲

Mr.*_*ard 32 wolfram-mathematica currying

可以使用以下结构在Mathematica中实现有限形式的Currying:

f[a_][b_][c_] := (a^2 + b^2)/c^2
Run Code Online (Sandbox Code Playgroud)

允许一个人做,例如:

f[4][3] /@ Range@5
Run Code Online (Sandbox Code Playgroud)
  {25, 25/4, 25/9, 25/16, 1}

有一个问题:Attributes只适用于第一个(一组)参数.考虑:

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]
Run Code Online (Sandbox Code Playgroud)
   {"2 + 2", "2", "8"}  

我的意图是返回"8 / 4",并"3 + 5"在列表中.


所以:

  • 有没有办法将属性扩展到此构造?

  • 是否有其他方便的结构来实现这一目标?

  • 除了属性之外,还有其他方法可以扩展Mathematica中的Currying吗?

Mat*_*att 18

我认为没有任何方法可以将属性应用于这种"upvalue"模式定义的后续部分.

一种替代方法是使用具有属性的纯函数.不像模式匹配那么方便,但是当你评估时f[2+2][8/4],它实际上给出了Curry喜欢的结果.("函数"是Mathematica的"lambda",如果你熟悉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}]]]

数学食谱呈现出完全不同的方式来讨好的73-77页.

作为一般准则,如果你试图控制Mathematica何时评估表达式,你会让自己痛苦不堪.在许多情况下,更好的方法是使用符号作为您不想评估的表达式的占位符,然后在评估其中时,您可以用符号的所需表达式替换.


Gri*_*lin 13

很抱歉可能没有相关评论.我刚搜索了"与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]
Run Code Online (Sandbox Code Playgroud)

它导致所需的携带:

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]
Run Code Online (Sandbox Code Playgroud)

并给出正确的结果: {"1+1", "2+2", "6+1"}}但它失败了f[1 + 1][2 + 2, 6 + 1].对于这个,可以使用更高级的版本:

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)
Run Code Online (Sandbox Code Playgroud)


WRe*_*ach 10

我不知道有任何方法可以将属性扩展到第二个或后来的curried参数列表 - 虽然我很想听到一个.

您可以使用纯函数实现与curried 表达式具有相同外观的表达式的定义(尽管我会毫不犹豫地将其称为"方便"):

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]
Run Code Online (Sandbox Code Playgroud)

对图案使用现在无证符号匹配咖喱表达成为可能HeadCompose:

In[65]:= MatchQ[g[x][y][z], HeadCompose[g, x_, y_, z_]]
Out[65]= True
Run Code Online (Sandbox Code Playgroud)

......虽然这种能力对手头的事情没有帮助. HeadCompose在几个版本之前已被弃用,最终被从文档中删除.但我不知道任何其他模式匹配curry表达式的方法.我推测它已经被弃用了,因为人们无法有效地将属性和定义附加到它上面,给它带来了可怕的状态:这个符号还没有完全集成到长期的Mathematica系统中,并且可能会发生变化.


Leo*_*rin 6

迟到了 - 所以不能直接回答这个问题(其他帖子已经很好地回答了).我只想指出,可以通过使用Stack和异常对评估进行非本地控制.这有点难看,但我认为它没有得到充分的探索.这是一个例子:

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]
Run Code Online (Sandbox Code Playgroud)

这使用了在元素之前递归地计算头的事实.你可以从这里看到的是,人们能够以这种方式提取未评估的参数,并且可以在进一步处理中使用它们.然而,计算被中断.还应该可以从中提取足够的信息Stack[_]以恢复计算.我不确定是否可以在Mathematica中实现延续,但如果是这样,那应该可能就是这些.


M. *_*gan 6

有一种方法可以自动完成.考虑这个功能

f[a_, b_, c_] := {a, b, c}
Run Code Online (Sandbox Code Playgroud)

为此,我们想让它隐含地"curryable",所以它可以通过以下任何一种方式调用:

f[1, 2, 3]
f[1, 2][3]
f[1][2][3]
Run Code Online (Sandbox Code Playgroud)

如果有一种方法可以自动生成以下定义(我们将在下面执行),则可以实现这一点:

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]]]
Run Code Online (Sandbox Code Playgroud)

正如Matt上面的另一个答案,我们只能做一个定义:f:= Funcion [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}]
Run Code Online (Sandbox Code Playgroud)

即使定义了任何这些符号,这也将按预期工作,就像SetDelayed可以工作一样.

此外,使用Notation包,您可以将其显示为赋值运算符; 说f [a_,b_,c]#= {c,b,a},但我没试过.

在下面的源代码中,我使用了一些可能与会话冲突的ad hoc符号,因此如果您打算使用它,请将其包含在包命名空间中.

完整代码:

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
Run Code Online (Sandbox Code Playgroud)

更新,现在属性(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]}
Run Code Online (Sandbox Code Playgroud)