Wolfram mathematica 讨好Mathematica
可以使用此构造在Mathematica中实现有限形式的:Wolfram mathematica 讨好Mathematica,wolfram-mathematica,currying,Wolfram Mathematica,Currying,可以使用此构造在Mathematica中实现有限形式的: f[a_][b_][c_] := (a^2 + b^2)/c^2 允许某人做,例如: f[4][3] /@ Range@5 {"2 + 2", "2", "8"} 我的意图是在列表中返回“8/4”和“3+5” 因此: 有没有办法将属性扩展到此构造 是否有其他方便的结构来实现这一点 除了属性之外,还有其他方法可以在Mathematica中扩展咖喱吗 我不知道有什么方法可以将属性扩展到第二个或更高版本的curried参数列表中——
f[a_][b_][c_] := (a^2 + b^2)/c^2
允许某人做,例如:
f[4][3] /@ Range@5
{"2 + 2", "2", "8"}
我的意图是在列表中返回“8/4”
和“3+5”
因此:
- 有没有办法将属性扩展到此构造
- 是否有其他方便的结构来实现这一点
- 除了属性之外,还有其他方法可以在Mathematica中扩展咖喱吗
HeadCompose
,对当前表达式进行模式匹配:
In[65]:= MatchQ[g[x][y][z], HeadCompose[g, x_, y_, z_]]
Out[65]= True
。。。尽管这种能力对手头的事情没有帮助
HeadCompose
在几个版本之前被弃用,最终从文档中删除。但我不知道还有什么其他的方式来匹配咖喱语。我推测,它之所以被弃用,正是因为人们无法有效地将属性和定义附加到它身上,给了它一种可怕的地位:这个符号尚未完全融入长期的Mathematica系统,并且可能会发生变化。我不认为有任何方法可以将属性应用到这样一个系统的后面部分“upvalue”模式定义
另一种方法是使用带属性的纯函数。不像模式匹配那样方便,但当您计算f[2+2][8/4]
时,它实际上给出了Curry想要的结果。(“函数”是Mathematica的“lambda”,如果您熟悉lambda演算。)
f=Function[a,Function[b,Function[c,HoldForm@{a,b,c},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]:=函数[args,body,HoldAll];设置属性[hf,HoldAll];
f=hf[a,hf[b,hf[c,HoldForm@{a,b,c}]]]
在第73-77页上,呈现了一种完全不同的咖喱方法
一般来说,如果你试图控制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]
这使用了这样一个事实,即头是在元素之前递归计算的。从这里您可以看到,人们能够以这种方式提取未计算的参数,并且可能可以在进一步的处理中使用它们。尽管计算被中断。还可以从
堆栈[\ux]中提取足够的信息恢复计算。我不确定是否可以在Mathematica中实现连续性,但是如果是的话,应该是沿着这些线。有一种方法自动完成。考虑函数
f[a_, b_, c_] := {a, b, c}
我们希望将其隐式地“curryable”,因此可以通过以下任何方式调用:
f[1, 2, 3]
f[1, 2][3]
f[1][2][3]
如果有一种方法可以自动生成以下定义(我们将在下面执行此操作),则可以实现这一点:
正如Matt在上面的另一个答案中所说,我们本可以只做一个定义:f:=Funcion[a,Function[b,Function[c,BODY]],但是我们将无法通过f[a,b,c]或f[a,b]调用f,只能将其称为f[a][b]或f[a][b][c]。有多个定义,我们可以选择其中一种样式
生成这些定义可以通过函数(定义如下)CurryableSetDelayed完成,只需调用:
CurryableSetDelayed[f[a_, b_, c_], {a, b, c}]
即使定义了这些符号中的任何一个,这也将按预期工作,就像SetDelayed工作一样
另外,使用Notation包,您可以将其显示为赋值运算符;比如f[a_uu,b_u,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
Update,now属性(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]}
抱歉,有一条可能不相关的评论。我刚刚搜索了“currying with 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”}
,但在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)
我相信我们可以用一个符号
f
来代替f
、f1
、f2
,这似乎更合适。@W先生同意,我们可以使用
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
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]}
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[1 + 1, 2 + 2, 6 + 1]
f[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)