11

I am developing a (large) package which does not load properly anymore. This happened after I changed a single line of code. When I attempt to load the package (with Needs), the package starts loading and then one of the setdelayed definitions “comes alive” (ie. Is somehow evaluated), gets trapped in an error trapping routine loaded a few lines before and the package loading aborts.
The error trapping routine with abort is doing its job, except that it should not have been called in the first place, during the package loading phase. The error message reveals that the wrong argument is in fact a pattern expression which I use on the lhs of a setdelayed definition a few lines later.

Something like this:

……Some code lines

Changed line of code 

g[x_?NotGoodQ]:=(Message[g::nogood, x];Abort[])

……..some other code lines

g/: cccQ[g[x0_]]:=True

When I attempt to load the package, I get:

g::nogood: Argument x0_ is not good

As you see the passed argument is a pattern and it can only come from the code line above.

I tried to find the reason for this behavior, but I have been unsuccessful so far. So I decided to use the powerful Workbench debugging tools .

I would like to see step by step (or with breakpoints) what happens when I load the package. I am not yet too familiar with WB, but it seems that ,using Debug as…, the package is first loaded and then eventually debugged with breakpoints, ect. My problem is that the package does not even load completely! And any breakpoint set before loading the package does not seem to be effective.

So…2 questions:

  1. can anybody please explain why these code lines "come alive" during package loading? (there are no obvious syntax errors or code fragments left in the package as far as I can see)
  2. can anybody please explain how (if) is possible to examine/debug package code while being loaded in WB?

Thank you for any help.

Edit

In light of Leonid's answer and using his EvenQ example: We can avoid using Holdpattern simply by definying upvalues for g BEFORE downvalues for g

notGoodQ[x_] := EvenQ[x];
Clear[g];
g /: cccQ[g[x0_]] := True
g[x_?notGoodQ] := (Message[g::nogood, x]; Abort[])

Now

?g

Global`g

cccQ[g[x0_]]^:=True



g[x_?notGoodQ]:=(Message[g::nogood,x];Abort[])



In[6]:= cccQ[g[1]]

Out[6]= True

while

In[7]:= cccQ[g[2]]

During evaluation of In[7]:= g::nogood: -- Message text not found -- (2)

Out[7]= $Aborted

So...general rule:

When writing a function g, first define upvalues for g, then define downvalues for g, otherwise use Holdpattern

Can you subscribe to this rule?

Leonid says that using Holdpattern might indicate improvable design. Besides the solution indicated above, how could one improve the design of the little code above or, better, in general when dealing with upvalues?

Thank you for your help

4

1 に答える 1

14

WB はさておき (質問に答えるのに実際には必要ありません) - 問題は、割り当て中に式がどのように評価されるかにのみ基づいて、簡単な答えを持っているようです。次に例を示します。

In[1505]:= 
notGoodQ[x_]:=True;
Clear[g];
g[x_?notGoodQ]:=(Message[g::nogood,x];Abort[])

In[1509]:= g/:cccQ[g[x0_]]:=True

During evaluation of In[1509]:= g::nogood: -- Message text not found -- (x0_)
Out[1509]= $Aborted

notGoodQそれを機能させるために、常に を返すように意図的に定義しましたTrue。では、なぜg[x0_]代入中に が評価されたのTagSetDelayedでしょうか? 答えは、TagSetDelayed(と同様にSetDelayed)代入では、あるかもしれh/:f[h[elem1,...,elemn]]:=...ないルールを適用しないが、それはと同様fに を評価するということです。次に例を示します。h[elem1,...,elem2]f

In[1513]:= 
ClearAll[h,f];
h[___]:=Print["Evaluated"];

In[1515]:= h/:f[h[1,2]]:=3

During evaluation of In[1515]:= Evaluated
During evaluation of In[1515]:= TagSetDelayed::tagnf: Tag h not found in f[Null]. >>
Out[1515]= $Failed  

という事実は、その引数を評価しないという意味でTagSetDelayedはありHoldAllません-それは、引数が評価されずに到着し、それらが評価されるかどうかがTagSetDelayed(上で簡単に説明した)のセマンティクスに依存することを意味するだけです。同じことが にも当てはまるためSetDelayed、「引数を評価しない」という一般的に使用されるステートメントは文字通り正しくありません。より正確なステートメントは、評価されていない引数を受け取り、それらを特別な方法で評価するというものです。rhs は評価しませんが、lhs の場合、head と要素を評価しますが、head のルールは適用しません。それを避けるために、次のように でラップすることができますHoldPattern:

Clear[g,notGoodQ];
notGoodQ[x_]:=EvenQ[x];
g[x_?notGoodQ]:=(Message[g::nogood,x];Abort[])
g/:cccQ[HoldPattern[g[x0_]]]:=True;

これは通じます。ここにいくつかの使用法があります:

In[1527]:= cccQ[g[1]]
Out[1527]= True

In[1528]:= cccQ[g[2]]
During evaluation of In[1528]:= g::nogood: -- Message text not found -- (2)
Out[1528]= $Aborted

ただしHoldPattern、定義を作成するときに左辺が必要な場合は、多くの場合、関数呼び出し中に頭の中の式も評価され、コードが壊れる可能性があることを示していることに注意してください。これが私が意味することの例です:

In[1532]:= 
ClearAll[f,h];
f[x_]:=x^2;
f/:h[HoldPattern[f[y_]]]:=y^4;

このコードは のようなケースをキャッチしようとしますが、評価が になる前に評価されるh[f[something]]ため、明らかに失敗します。f[something]h

In[1535]:= h[f[5]]
Out[1535]= h[25]

私にとってHoldPattern、lhs の必要性は、自分のデザインを再考する必要があるというサインです。

編集

WB でのロード中のデバッグに関して、できることの 1 つ (IIRC、現在は確認できません) は、古き良き print ステートメントを使用することです。その出力は WB のコンソールに表示されます。個人的には、この目的 (ロード時のパッケージのデバッグ) でデバッガーの必要性を感じることはほとんどありません。

編集2

質問の編集に応じて:

定義の順序について: はい、これを行うことができ、この特定の問題を解決します。しかし、一般的に、これはロバストではなく、一般的な良い方法とは言えません。少し文脈から外れているので、当面のケースに明確なアドバイスを与えるのは難しいですが、UpValuesここでの使用は不当であるように私には思えます. これがエラー処理のために行われる場合、 を使用せずに行う方法は他UpValuesにもあります。

一般に、UpValuesオーバーロードされる関数にルールを追加せずに、安全な方法で関数をオーバーロードするために最も一般的に使用されます。UpValuesアドバイスの 1 つは、評価する可能性のある頭との関連付けを避けるDownValuesことです。これを行うと、評価者とのゲームを開始し、最終的には負けます。UpValues最も安全なのは、特定の関数をオーバーロードするオブジェクトの「タイプ」を表すことが多い不活性シンボル (ヘッド、コンテナー) にアタッチすることです。

HoldPattern悪いデザインを示す存在についての私のコメントについて。確かHoldPattern、次の (やや人為的な) ような の正当な使用法があります。

In[25]:= 
Clear[ff,a,b,c];
ff[HoldPattern[Plus[x__]]]:={x};
ff[a+b+c]

Out[27]= {a,b,c} 

多くの場合Plus、未評価のままであり、未評価の形で有用であるため、ここでは正当化されます。これは、合計を表すと推測できるためです。ここが必要なHoldPatternのは、方法Plusが単一の引数で定義されているためです。パターンは、定義中にたまたま単一の引数 (通常は複数の引数を記述しているにもかかわらず) になるためです。したがって、HoldPatternここではパターンを通常の引数として扱うことを防ぐために使用していますが、これは の意図した使用例とはほとんど異なりPlusます。このような場合はいつでも (定義が意図したユース ケースで問題なく機能すると確信しています)、HoldPattern問題ありません。ところで、この例も壊れやすいことに注意してください。

In[28]:= ff[Plus[a]]
Out[28]= ff[a]

それでもほとんど問題ない理由は、通常Plus、単一の引数で使用しないためです。

ただし、通常提供される引数の構造が、定義に使用されるパターンの構造と同じである場合の 2 番目のグループがあります。この場合、割り当て中のパターン評価は、関数呼び出し中に実際の引数で同じ評価が行われることを示しています。使用状況はこのカテゴリに分類されます。設計上の欠陥に対する私のコメントは、そのような場合に対するものでした。パターンが評価されないようにすることはできますが、これを機能させるには、引数も同様に評価されないようにする必要があります。また、完全に評価されていない式に対するパターン マッチングは脆弱です。また、関数は、引数に対して (型チェックできる範囲を超えた) 特別な条件を想定してはなりません。

于 2011-09-14T00:16:17.800 に答える