8

私はルビーに恋をしています。この言語では、すべてのコア関数は実際にはメソッドです。そのため、処理したいデータが匿名処理関数の本体から左に配置されている場合、後置表記を好みます。たとえば、array.map{...}. このコードが読みやすいという利点があると思います。

しかし、Mathetic は機能的であるため (必要に応じて手続き型にすることもできます)、関数名がデータの左側に配置されるスタイルが決まります。マニュアルでわかるように、//は、 のような引数のない単純な関数の場合にのみ使用されlist // MatrixFormます。Function が多くの引数を必要とする場合、マニュアルを書いた人は syntax を使用しますF[data]
大丈夫ですが、私の問題は、F[f,data]たとえばDo[function, {x, a, b}]. ほとんどの Mathematica 関数は(すべてではないにしても)引数を正確にこの順序で持っています –[function, data]ではなく[data, function]. ノートブックに名前付き関数をたくさん作成するのではなく、純粋な関数を使用して名前空間をきれいに保つことを好むので、引数functionが大きすぎる可能性があります。data関数呼び出しのある行の後のコードの 5 ~ 20 行目に配置されます。

これが、邪悪なRuby の性質が私を制御下に置いたときに、そのような関数を後置式に書き直す理由です。

Do[f (x), {x, a, b}]\n{x, a, b} // Do[f (x), #] &

私にとっては重要なので、その純粋な関数 (潜在的に大きなコード) はデータ処理からすぐに配置されます。ええ、私はそれを行い、私は幸せです。しかし、次の 2 つのことがあります。

  1. これにより、Mathematica の強調表示パーサーの問題が発生xします。後置記法は青緑色ではなく青色で強調表示されます。
  2. Mathematica のマニュアルを調べるたびに、次のような例を目にします: Do[x[[i]] = (v[[i]] - U[[i, i + 1 ;; n]].x[[i + 1 ;; n]])/ U[[i, i]], {i, n, 1, -1}];、つまり、彼らは、Mathematica が読みやすい/サポートしやすい/などと考えているということです?!

これらの 2 つのことから、ここでこの質問をするようになりました: Ruby スタイルを使用する私はとても悪い少年ですか?これらの人のようにコードを書くべきですか、それとも大丈夫ですか? 心配する必要はありません。好きなように書く?

4

6 に答える 6

10

あなたが提案するスタイルはしばしば可能ですが、の場合はお勧めできませんDo。問題はDo、属性があることですHoldAllxループ変数 (例では) は評価されず、ローカル変数として扱われる必要があるため、これは重要です。これを確認するには、次の式を評価してみてください。

x = 123;

Do[Print[x], {x, 1, 2}]
(* prints 1 and 2 *)

{x, 1, 2} // Do[Print[x], #]&
(* error: Do::itraw: Raw object 123 cannot be used as an iterator.
   Do[Print[x], {123, 1, 2}]
*)

Do[Print[x], #]&純粋な関数にはHoldAll属性がなく、{x, 1, 2}評価されるため、エラーが発生します。HoldAllこの問題は、属性を使用して純粋な関数を明示的に定義することで解決できます。したがって、次のようになります。

{x, 1, 2} // Function[Null, Do[Print[x], #], HoldAll]

...しかし、治療は病気よりも悪いと思います:)

Doしたがって、Table、などの「バインディング」表現を使用してModuleいる場合は、群れに準拠するのが最も安全です。

于 2011-08-17T16:25:18.733 に答える
8

Mathematicaが最も自然にサポートするスタイルの使い方を学ぶ必要があると思います.確かに複数の方法があり、私のコードは他の人のコードとは異なります。それにもかかわらず、 Mathematicaの構文を別の言語に基づいて独自の先入観を持ったスタイルに打ち負かそうとし続けるなら、私はあなたに不満が続くことを予見します.

空白は悪ではなく、長い引数を区切るために改行を簡単に追加できます。

Do[
  x[[i]] = (v[[i]] - U[[i, i + 1 ;; n]].x[[i + 1 ;; n]]) / U[[i, i]]
  , {i, n, 1, -1}
];

これは、通常目にするより多くの接頭辞 ( f @ x) と中置 ( x ~ f ~ y) 表記を使用して書くのが好きであり、そのような関数がそれぞれ 1 つと 2 つの引数を受け取ることを簡単に判断できるため、これは価値があると思います。これはやや標準的ではありませんが、 Mathematica構文の痕跡を消し去っているとは思いません。むしろ、構文を有利に使用していると思います。これにより、構文の強調表示が失敗することがありますが、私はそれを受け入れることができます。

f[x] ~Do~ {x, 2, 5} 

f[x, y, z](必要に応じて改行を入れて)の標準形式以外のものを使用する場合は、評価の順序にもっと注意する必要があり、IMHO、読みやすさが損なわれる可能性があります。この不自然な例を考えてみましょう:

{x, y} // # + 1 & @@ # &

これは直感的にわかりません。はい、Mathematica の演算順序に詳しい人にとっては読みやすいですが、明確さは向上しないと思います。//読み取りが自然な名前付き関数の接尾辞を予約する傾向があります。

Do[f[x], {x, 10000}] //Timing //First
于 2011-08-17T16:09:44.713 に答える
7

たまたま後者をよく知っていて気に入っているという理由だけBで、言語の慣用的な方法で言語でプログラムを試すことは最大の間違いの1つだと思います。Aイディオムを借りることは悪いことではありませんが、第二言語を十分に理解して、他の人がそのように使用する理由を理解する必要があります。

あなたの例の特定のケースでは、一般的に、他の人が言及しなかったいくつかのことに注意を向けたい. 1Doつ目は、動的スコープを使用してイテレータ シンボルをローカライズするスコープ コンストラクトです。したがって、次のようになります。

In[4]:= 
x=1;
{x,1,5}//Do[f[x],#]&

During evaluation of In[4]:= Do::itraw: Raw object 
1 cannot be used as an iterator. >>

Out[5]= Do[f[x],{1,1,5}]

なんて驚きですね。Doこれは、標準的な方法で使用する場合には発生しません。

第二に、この事実はほとんど無視されていますが、常に と同じでf[#]&[arg]ないf[arg]ことに注意してください。例:

ClearAll[f];
SetAttributes[f, HoldAll];
f[x_] := Print[Unevaluated[x]]

f[5^2]

5^2

f[#] &[5^2]

25

これはあなたの例には影響しませんが、スコープを操作するため、使用法はこれによって影響を受けるケースに十分近いです。

于 2011-08-17T16:24:27.490 に答える
6

Mathematica は関数を引数に適用する4つの方法をサポートしています:

  1. 標準関数形式:f[x]
  2. プレフィックス:f@xまたはg@@{x,y}
  3. 接尾辞: x // f、および
  4. infix:x~g~yと同等g[x,y]です。

どのフォームを使用するかはあなた次第であり、何よりも美的な選択であることがよくあります。内部的にf@xは、 と解釈されf[x]ます。個人的には、チェーン内の各関数を変換と見なし、そのように複数の変換をつなぎ合わせる方が簡単なので、主にあなたのように後置を使用します。とは言うものの、私のコードには、主に気まぐれに応じて、標準形式と接頭辞形式の両方が散らばっていますが、関数のパラメーターに関して封じ込めの感覚を呼び起こすため、標準形式をより使用する傾向があります。

( ) の横に省略形のApply( ) を含めたので、接頭辞の形式を少し自由にしました。組み込みコマンドのうち、追加の作業なしで関数に複数の変数を簡単に渡すことができる のは、標準形式、中置形式のみです。(例: )は、式 ( ) の を関数に置き換えることで機能します。つまり、関数を複数の変数 ( ) で評価します。 @@Prefix@ApplyApplyg @@ {x,y}Head{x,y}g@@{x,y} == g[x,y]

後置形式を使用して関数に複数の変数を渡すために使用する方法は、リストを使用することです。私が書かなければならないので、これにはもう少し作業が必要です

{x,y} // f[ #[[1]], #[[2]] ]&

のどの要素がList適切なパラメータに対応するかを指定します。Apply私はこれを行う傾向がありますが、これを好きなものと組み合わせることができます

{x,y} // f @@ #&

これにより、タイピングが少なくなりますが、後で読むときに解釈が難しくなる可能性があります。

編集f:とg上記 は単なるプレースホルダーであり、純粋な関数に置き換えることができ、多くの場合、#+1& @ xとほぼ同等であることを指摘する必要があります。Leonid's answer#+1&[x]を参照してください。

明確にするために、 Leonid's answerに従って、f@exprとの間の同等性は、 に渡される前に式が評価されるのを防ぐ属性を持っていないf[expr]場合に true です。たとえば、 of の 1 つは、外部の影響を元に戻すことなくパラメータを内部で評価できるようにするスコープ構造として機能できるようにするものです。ポイントはに渡される前に評価されるため、未評価のままにしておく必要がある場合は、スタイル属性を持つ純粋な関数を作成するなど、特別な注意を払う必要があります。fexprfAttributesDoHoldAllexprfHold

于 2011-08-17T16:11:38.480 に答える
5

あなたが明らかに知っているように、あなたは確かにそれを行うことができます。個人的には、マニュアルがどのようにコードを書いているかは気にせず、自然で記憶に残る方法で書いてください。

しかし、私は通常、特定のパターンに陥っていることに気付きました。たとえば、計算後にリストを作成し、それが期待どおりであることを確認するために偶然にそれをプロットした場合、通常は次のようにします

prodListAfterLongComputation[
    args,
]//ListPlot[#,PlotRange->Full]&

たとえば、リストがありlst、複雑なプロットの作成に集中しているとします。

ListPlot[
    lst,
    Option1->Setting1,
    Option2->Setting2
]

したがって、基本的に、偶発的で、おそらく読み取り可能であることが重要ではないものはすべて (コードのそのビットのポイントではないため、最初のものを即座に解析できる必要はありませんListPlot)、すでに中断されないようにするために、後置になります。それが適用される複雑なコードを記述します。逆に、複雑なコードは、後で解析しやすい方法で書く傾向があります。私の場合は、次のようなものです。

f[
    g[
        a,
        b,
        c
    ]
]

ただし、より多くの入力が必要であり、Workbench/Eclipse プラグインを使用しない場合は、コードの再編成がより簡単になります。

したがって、「読みやすさの必要性と、コードの強調表示、コードをリファクタリングするための余分な作業などの利便性が失われる可能性を考慮した上で、最も便利なことは何でもする」とあなたの質問に答えると思います。

もちろん、コードの一部を扱っているのがあなただけである場合、これはすべて当てはまります。他にある場合、それはまったく別の問題です。

しかし、これは単なる意見です。これ以上のものを提供できる人はいないと思います。

于 2011-08-17T16:10:25.750 に答える
1

1つの引数の関数の場合(f@(arg))((arg)//f)およびf[arg]は、の属性を適用するという意味でも完全に同等ですf。マルチ引数関数の場合、次のように書くf@Sequence[args]Sequence[args]//f、同じ効果があります。

In[1]:= SetAttributes[f,HoldAll];
In[2]:= arg1:=Print[];
In[3]:= f@arg1
Out[3]= f[arg1]
In[4]:= f@Sequence[arg1,arg1]
Out[4]= f[arg1,arg1]

したがって、後置記法が好きな人のための解決策は、次を使用することであるようSequenceです:

x=123;
Sequence[Print[x],{x,1,2}]//Do
(* prints 1 and 2 *)

SequenceHold属性またはHoldAllComplete:を持つ関数では、いくつかの問題が発生する可能性があります。

In[18]:= Select[{#, ToExpression[#, InputForm, Attributes]} & /@ 
   Names["System`*"], 
  MemberQ[#[[2]], SequenceHold | HoldAllComplete] &][[All, 1]]

Out[18]= {"AbsoluteTiming", "DebugTag", "EvaluationObject", \
"HoldComplete", "InterpretationBox", "MakeBoxes", "ParallelEvaluate", \
"ParallelSubmit", "Parenthesize", "PreemptProtect", "Rule", \
"RuleDelayed", "Set", "SetDelayed", "SystemException", "TagSet", \
"TagSetDelayed", "Timing", "Unevaluated", "UpSet", "UpSetDelayed"}
于 2011-08-17T18:12:02.267 に答える