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系统中,并且可能会发生变化.
迟到了 - 所以不能直接回答这个问题(其他帖子已经很好地回答了).我只想指出,可以通过使用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中实现延续,但如果是这样,那应该可能就是这些.
有一种方法可以自动完成.考虑这个功能
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)