33

この構成を使用して、Mathematicaで限定された形式のカリー化を実装することができます。

f[a_][b_][c_] := (a^2 + b^2)/c^2

たとえば、次のようにします。

f[4][3] /@ Range@5
  {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]
   {"2 + 2"、 "2"、 "8"} 

"8 / 4"私の意図は、"3 + 5"リストに戻ることでした。


その結果:

  • この構成に属性を拡張する方法はありますか?

  • これを達成するための別の便利な構成はありますか?

  • 属性以外に、Mathematica内でカリー化を拡張する方法はありますか?

4

5 に答える 5

18

このような「アップバリュー」パターン定義の後の部分に属性を適用する方法はないと思います。

1つの代替方法は、属性を持つ純粋関数を使用することです。パターンマッチングほど便利ではありませんが、評価するf[2+2][8/4]と、実際にはカレーが好む結果が得られます。(ラムダ計算に精通している場合、「関数」はMathematicaの「ラムダ」です。)

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}]]]

Mathematicaクックブックは、73-77ページにカリー化へのかなり異なるアプローチを示しています。

一般的なガイドラインとして、Mathematicaが式を評価するタイミングを制御しようとすると、自分自身が惨めになります。多くの状況でのより良いアプローチは、まだ評価したくない式のプレースホルダーとしてシンボルを使用することです。そして、評価するときが来たら、シンボルの代わりに目的の式を使用できます。

于 2011-04-16T16:44:13.823 に答える
15

おそらく無関係なコメントでごめんなさい。«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}}

引数の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)
于 2012-07-19T13:21:50.317 に答える
10

属性を2番目以降のカレー引数リストに拡張する方法を私は知りません-私は1つについて聞きたいのですが。

純粋関数を使用して、カレー式と同じ外観の式の定義を実装できます(ただし、「便利」と呼ぶのは躊躇します)。

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]

現在文書化されていない記号を使用して、カレー式をパターンマッチングすることHeadComposeできます。

In[65]:= MatchQ[g[x][y][z], HeadCompose[g, x_, y_, z_]]
Out[65]= True

...この機能は当面の問題には役立ちませんが。 HeadCompose数バージョン前に非推奨になり、最終的にドキュメントから削除されました。しかし、私はカレー表現をパターンマッチングする他の方法を知りません。属性や定義を効果的に付けることができず、恐ろしい状況になっているため、非推奨になったと推測します。このシンボルは、長期のMathematicaシステムに完全に統合されておらず、変更される可能性があります。

于 2011-04-16T14:22:40.473 に答える
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]

これは、ヘッドが要素の前に再帰的に評価されるという事実を使用しています。ここからわかるのは、この方法で未評価の引数を抽出でき、おそらくそれらをさらなる処理に使用できることです。ただし、計算は中断されます。Stack[_]から計算を再開するのに十分な情報を抽出することも可能であるはずです。Mathematicaで継続を実装できるかどうかはわかりませんが、もしそうなら、それはおそらくこれらの線に沿っているはずです。

于 2011-04-17T21:34:50.413 に答える
6

それを自動的に行う方法があります。関数を考えてみましょう

f[a_, b_, c_] := {a, b, c}

暗黙的に「カレー可能」にしたいので、次のいずれかの方法で呼び出すことができます。

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]]]

上記の他のMattの回答と同様に、f:= Funcion [a、Function [b、Function [c、BODY]]]という1つの定義しか実行できませんでしたが、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]}
于 2011-11-16T06:29:32.123 に答える