One may implement a limited form of Currying in Mathematica, using this construct:
f[a_][b_][c_] := (a^2 + b^2)/c^2
Allowing one to do, for
I'm not aware of any way to extend attributes to the second or later curried argument lists -- although I'd love to hear about one.
You can implement definitions for expressions with the same appearance as the curried expression by using pure functions (although I would hesitate to call it "convenient"):
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]
It is possible to pattern match a curried expression using the now undocumented symbol HeadCompose
:
In[65]:= MatchQ[g[x][y][z], HeadCompose[g, x_, y_, z_]]
Out[65]= True
... although this capability does not help in the matter at hand. HeadCompose
was deprecated a few versions ago, to the point of it finally being removed from the documentation. But I am not aware of any other way to pattern-match curried expressions. I speculate that it was deprecated precisely because one cannot effectively attach attributes and definitions to it, giving it that dreaded status: This symbol has not been fully integrated into the long-term Mathematica system, and is subject to change.
I don't think there is any way to have attributes apply to the later parts of such an "upvalue" pattern definition.
One alternative is to use pure functions with attributes. Not as convenient as pattern matching, but when you evaluate f[2+2][8/4]
, it actually gives a result Curry would have liked. ("Function" is Mathematica's "lambda", if you're familiar with lambda calculus.)
f = Function[a,Function[b,Function[c,HoldForm@{a,b,c},HoldAll],HoldAll],HoldAll]
I presume you want to be able to do something like the following:
f[2+2][2/1] /@ Unevaluated@{1+1,3+3}
→ {{2+2, 2/1, 1+1}, {2+2, 2/1, 3+3}}
If you're going to do this sort of thing often, you can make it slightly easier to type in:
hf[args_,body_]:=Function[args,body,HoldAll]; SetAttributes[hf,HoldAll];
f = hf[a, hf[b, hf[c, HoldForm@{a, b, c}]]]
The Mathematica Cookbook presents a rather different approach to Currying on pages 73-77.
As a general guideline, if you try to control when Mathematica evaluates expressions, you will make yourself miserable. A better approach in many situations is to use symbols as placeholders for the expressions you don't want evaluated yet, and then when the time comes to evaluate one, you can substitute the desired expression for the symbol.
There is a way to do it automatically. Consider the function
f[a_, b_, c_] := {a, b, c}
for which we want to make it implicitly "curryable", so it could be called in any of these ways:
f[1, 2, 3]
f[1, 2][3]
f[1][2][3]
This could be achieved if there is a way to generate the following definitions automatically (which we do below):
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]]]
As in the other answer above by Matt, we could have done only one definition: f:=Funcion[a,Function[b,Function[c, BODY]]], but then we will not be able to call f via f[a,b,c] or f[a,b], and will have to call it only as f[a][b] or f[a][b][c]. With multiple definitions we can choose either styles.
Generating these definitions could be done by the function (defined below) CurryableSetDelayed, simply by calling:
CurryableSetDelayed[f[a_, b_, c_], {a, b, c}]
This will work as expected even if any of these symbols is defined, just like SetDelayed would work.
Also, with Notation package you could make it appear as an assignment operator; say f[a_,b_,c]#={c,b,a}, but I didn't try it.
In the source below I use some ad hoc symbols which may conflict with the session, so if you are going to use this, enclose it in a package namespace.
The full code:
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 Attributes (HoldAllComplete,etc.) extends to all parameters, so the following works as expected, as long as you set the attributes before calling 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]}
Sorry for a probably unrelated comment. I just searched «currying with Mathematica» and this question was the first in Google list. Although, it is 1 year old and already got answer, I found that the solutions presented are not quite elegant imho. The simple modification of the initial code should be as follows:
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]
It results in the desired carrying:
f[2+2][2+1] /@ Unevaluated@{1+1, 3+3}
→ {{2+2, 2+1, 1+1}, {2+2, 2+1, 3+3}}
It works fine for three possible partitions of arguments
f[1 + 1, 2 + 2, 6 + 1]
f[1 + 1, 2 + 2][6 + 1]
f[1 + 1][2 + 2][6 + 1]
and gives the correct result:
{"1+1", "2+2", "6+1"}}
, but it fails for f[1 + 1][2 + 2, 6 + 1]
. For this one, one can use a little bit more advanced version:
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)
Coming late to the party - so not a direct answer to the question (which has been answered by other posts quite well). I just want to point out that one can have a form of non-local control over the evaluation by using Stack
and exceptions. It is a bit ugly, but I don't think it has been fully explored. Here is an example:
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]
This uses the fact that heads are evaluated before elements, recursively. What you can see from here is that one is able to extract the unevaluated arguments in this way, and can, perhaps, use them in further processing. The computation is interrupted though. It should also be possible to extract enough information from the Stack[_]
to resume the computation. I am not sure whether one can implement continuations in Mathematica, but if so, that should be probably along these lines.