ソースレベルの演算子が実際に将来のある時点で実行される操作を記述し、実際の演算子をそのオペランドと一緒にサンクする場合。
これに一般的な名前があるのか、それとも「パターン」とは思えないほど低レベルのデザイン要素なのかはわかりませんが、とにかく多くの状況でよく見られる要素です。 :
問題のツールを使用する唯一の方法であるため、すべての場合にアンチパターンではないことは明らかです(ただし、Cで実行すると1つのビートが発生する可能性があります)。それ自体が「グリーンスパニング」や「EDSLの使用」ではないと思います。それよりも一般的で広く適用できるからです。インタープリターパターンではないと思いますが、正しく理解していない可能性があります。計算はホスト言語コードを実行することによって直接構築されます(したがって、コンパイル時に効果的に存在しますが、通常はファーストクラスの言語としては存在しません)文字列または他のランタイムロードデータから解析されるのではなく、コンストラクト)。
すべての場合において、実際にそのアクションをパッケージ化しながら、操作が1つのことを実行しているように見えます(Cであり、+をオーバーロードする代わりにAddを書き出す必要がある場合は、必ずしも説得力があるとは限りません)。後で消費するために。 「計算ビルダー」パターンのようなものですか?しかし、私はその用語が使用されているのを見つけていません。
ここで解決する実際的な問題はありません。名前を付けることができない共通のデザイン要素があるように思われるのは、私を悩ませているだけです。
(質問はもともとStackOverflowに投稿され、手作業で移動されました)
あなたが説明しているように見えるのは遅延評価。結果がソースコードに表示されるときではなく、結果が必要なときに実行される計算です。
Haskellでは、これはこれらの計算をモナド抽象化の背後に隠すことによって行われます。 C++では、抽象化は似ていますが、より明示的であり、オーバーロードされた演算子と式テンプレートの背後に部分的に隠されています。
同様に、CでのLISPのような構造の「Greenspunning」の引用例はアンチパターンではなく、データ駆動型の遅延評価DSLであり、実際には、FFIの最も一般的なパターンの1つであるように思われます。 Cには未実行の関数をデータとして構築して渡す手段がないため、LISPおよびSchemeインタープリター(特にECL、Chicken、tinyschemeなど)。
これらのパターンは、ファーストクラスの関数オブジェクトを持つ言語では表示されないことに気付くでしょう。
これは遅延評価と呼ばれます。これは非常に一般的なパターンです。実際、Cのような言語で&&
または||
演算子を使用するたびに、2番目のオペランドは必要な場合にのみ評価されます。同様に、if
/then
/else
では、ブランチの1つだけが評価されます。
遅延評価にはいくつかの興味深い特性があります。
副作用がない場合、何かを怠惰にすることはプログラムの結果を変えることはできません。 canただし、非終了プログラムを終了させます。たとえば、次のようなものがある場合:
False && infiniteLoop
熱心な評価では、これは無限ループになりますが、遅延評価では、これはFalse
を返します。
IOW:遅延評価により、先行評価では作成できないプログラムを作成できます。 Haskellの有名なフィボナッチ数列の例を考えてみましょう。
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
[これは悪い例です、ところで、それは最適なアルゴリズムの複雑さを持っていないので。]
With副作用ただし、遅延評価により、副作用が発生する順序が変わる場合があります。または、発生しない場合もありますまったく。
純粋なプログラムと完全なプログラムの場合、遅延評価と先行評価の変更まったくない、それは単にコンパイラーの最適化の選択になります。 (プログラム全体は常に終了し、熱心評価と遅延評価の唯一の違いは終了です。したがって、プログラム全体では違いはありません。)
これはまったく遅延評価ではありません。それは完全に独立したものです。
Haskellでは、このパターンは通常、コンビネーターと一緒に発生します。ただし、コンビネーターでは、他の形式の計算を模倣する必要はありません。 (私はおそらくそれを何らかの形の「しゃれ」を模倣していると呼ぶでしょう。)