Есть способ сделать это автоматически.Рассмотрим функцию
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]]]
Как и в другом ответе Мэтта выше, мы могли бы сделать только одно определение: 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}]
Это будет работать, как ожидается, даже еслилюбой из этих символов определен, точно так же, как SetDelayed будет работать.
Кроме того, с пакетом Нотации вы можете сделать так, чтобы он отображался как оператор присваивания;скажем 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]}