これは私がかなり長い間使ってきたバージョンです(本来、私の本の第2版のために書いたものですが、私はそれをたくさん使ってしまいました)。引数が評価されていないコードを表している場合、特定の1つの句を表す1つのコードが未評価の形で渡されるようにするには、テスト関数にHoldAll
またはHoldFirst
の属性が必要です(望ましい場合もあります)。
ClearAll[fastOr];
Attributes[fastOr] = {HoldRest};
fastOr[test_, {args___}] := fastOr[test, args];
fastOr[test_, args___] :=
TrueQ[Scan[
Function[arg, If[test[arg], Return[True]], HoldAll],
Hold[args]]];
編集:私はちょうど疑問にリンクされたページの下部にあるダニエル・リーブスにより、溶液は、これと非常に似ていることに気づきました。主な違いは、短絡と引数の評価が未評価であることです(下記参照)。一方、Danielは短絡部分のみに焦点を当てています。
これは短絡動作をしています。引数を未評価の形で保存したいので、HoldRest
属性が必要です。 test
に渡されるまで未評価の各引数を保持するために、純関数内にHoldAll
(またはHoldFirst
)属性も必要です。それがtest
の本文で使用される前に評価されるかどうかは、今度はtest
の属性に依存します。例として:
ここでは、副作用(印刷)を引き起こすいくつかのコードを引数として渡す例を示します。 fastOr
がOr
のための句として評価されないコードの一般的な部分を受け入れているので、あなたがする必要がある、ということ
In[15]:= fastOr[# &, Print["*"]; False, Print["**"]; False,
Print["***"]; True, Print["****"]; False]
During evaluation of In[15]:= *
During evaluation of In[15]:= **
During evaluation of In[15]:= ***
Out[15]= True
注:結果はすでに前項で決定されているので、最後の引数のコードは、実行する機会を持っていません上記のRange
の例のように、開始時に評価されても構わない場合は、Evaluate
に値リストをラップしてください。
最後に、fastOr
の保留コードのプログラムによる構成を説明し、その使用方法を示します(必要に応じて、保持された式を使用した小さなクラッシュコースと考えてください)。手持ち式を使用する際は、次の機能は非常に便利です:
joinHeld[a___Hold] := Hold @@ Replace[Hold[a], Hold[x___] :> Sequence[x], {1}];
例:ここでは
In[26]:= joinHeld[Hold[Print[1]], Hold[Print[2], Print[3]], Hold[], Hold[Print[4]]]
Out[26]= Hold[Print[1], Print[2], Print[3], Print[4]]
は、我々はプログラムで印刷-Sでの例で使用された開催された引数を構築するためにそれを使用する方法です上:
In[27]:=
held = joinHeld @@ MapThread[Hold[Print[#]; #2] &,
{NestList[# <> "*" &, "*", 3], {False, False, True, False}}]
Out[27]= Hold[Print["*"]; False, Print["**"]; False, Print["***"]; True, Print["****"]; False]
はfastOr
にそれを渡すために、私たちは別の有用なイディオムを使用します。我々は、すべて取得するまでHold[args]
に追加(または先頭に追加)関数の引数、その後、Apply
を使用します(一般的なイディオムがAppend[Hold[parts___],Unevaluated[newpart]]
のように見えるように、我々は我々が追加されている作品をしたくない場合は、一般的には、それを注意/評価するために、先頭に追加し、我々は、Unevaluated
でそれをラップする必要があります):
In[28]:= fastOr @@ Prepend[held, # &]
During evaluation of In[28]:= *
During evaluation of In[28]:= **
During evaluation of In[28]:= ***
Out[28]= True
あなたが参照している元の実装に関して、あなたは私が以前に作ったコメントを見ることができます。問題は、TakeWhileとLengthWhileにv.0.0.0のパックド配列のバグがあり、8.0.1のソースで修正されていることです。つまり、8.0.1から、私のバージョンかMichaelバージョンを使用できます。
HTH
編集:
私はちょうどあなたが言及記事で、あなたは別の構文を望んでいたことに気づきました。このケースに対してfastOr
で取られたアプローチを採用することはそれほど難しくありませんが、ここでは異なる実装があります。これは間違いなく、この特定の構文の既存の言語構造とよりよく対応しています。 Table
と例外を使用することをお勧めします。これは、Table
のイテレータが同じ構文を受け入れるためです。ここでは、次のとおりです。
ClearAll[AnyTrue, AllTrue];
SetAttributes[{AnyTrue, AllTrue}, HoldAll];
Module[{exany, exall},
AnyTrue[iter : {var_Symbol, lis_List}, expr_] :=
TrueQ[Catch[Table[If[TrueQ[expr], Throw[True, exany]], iter], exany]];
AllTrue[iter : {var_Symbol, lis_List}, expr_] :=
Catch[Table[If[! TrueQ[expr], Throw[False, exall]], iter], exall] =!= False;
];
説明のいくつかの単語:私たちは一度だけ定義する必要がカスタム例外タグ以来のトップレベルにモジュールを使用し、同様の定義時にそれを行うことができます。表から脱出する方法は例外を通じたものです。それほどエレガントではなく、小さなパフォーマンスヒットを引き起こしますが、Table
によって行われるイテレータ変数の自動動的ローカライゼーションとシンプルさを購入しています。これを安全な方法で行うには、一意のタグで例外にタグを付ける必要があります。したがって、誤って他の例外を検出することはありません。永続的な例外タグを作成するためにモジュールを使用することは、一般的に非常に便利なトリックとなることがわかりました。さて、いくつかの例は: - これはTable
によって考慮される
In[40]:= i = 1
Out[40]= 1
In[41]:= AnyTrue[{i, {1, 2, 3, 4, 5}}, i > 3]
Out[41]= True
In[42]:= AnyTrue[{i, {1, 2, 3, 4, 5}}, i > 6]
Out[42]= False
In[43]:= AllTrue[{i, {1, 2, 3, 4, 5}}, i > 3]
Out[43]= False
In[44]:= AllTrue[{i, {1, 2, 3, 4, 5}}, i < 6]
Out[44]= True
In[45]:= AllTrue[{a, {1, 3, 5}}, AnyTrue[{b, {2, 4, 5}}, EvenQ[a + b]]]
Out[45]= True
In[46]:= AnyTrue[{a, {1, 3, 5}}, AllTrue[{b, {2, 4, 5}}, EvenQ[a + b]]]
Out[46]= False
私は、反復子変数の可能なグローバル値は重要でないことを示すために、i
への割り当てを開始します。
lst
はリストを表しているという事実から
In[47]:= lst = Range[5];
AllTrue[{i, lst}, i > 3]
Out[48]= AllTrue[{i, lst}, i > 3]
(:最後に、(私は他の場所でコメントしたように)、AllTrue
とAnyTrue
のためのあなたのオリジナルの署名は、以下が動作しないという意味で、少しも限定的であることに注意してくださいHoldAll
属性のため、パターンマッチング時には分かりません)。この動作を維持する正当な理由はないので、_List
のチェックを削除することができます。AnyTrue[iter : {var_Symbol, lis_}, expr_]
と同様にAllTrue
を使用します。このクラスの使用例について説明します。
パフォーマンスの影響についてはわかりませんが、ほとんどの場合、LengthWhile [FromPackedArray @ lis'、...作品 –
はい、これは私が今使っているものですが、私はこの種のタスクの全体的なスタイルにもっと興味があります –
ドキュメントから** ToPackedArrayを使用してもMathematicaで生成された結果は変わりません** ... lier!リアー!火のズボン! –