web-dev-qa-db-ja.com

この(アンチ?)パターンは何と呼ばれていますか? (またはそれを説明する方法)

ソースレベルの演算子が実際に将来のある時点で実行される操作を記述し、実際の演算子をそのオペランドと一緒にサンクする場合。

これに一般的な名前があるのか​​、それとも「パターン」とは思えないほど低レベルのデザイン要素なのかはわかりませんが、とにかく多くの状況でよく見られる要素です。 :

  • 私が正しく理解している場合(頻繁なC++ユーザーではない)、Boost :: Phoenixはこれを実行して、ラムダとレイジー操作を表します。 +をオーバーロードして、型の実際の+関数とともに引数を実際にキャプチャします
  • 関数型言語(またはSpiritのようなもの)のパーサーコンビネーターはデータの演算子のように見えますが、実際には後で実行されるパーサーを構築します
  • 他のEDSL(演算子のオーバーロードがある言語)はこれを頻繁に行うようです。関数型リアクティブプログラミングライブラリは、操作が現在実行しているように見えることを実行するプロシージャを目に見えない形で構築する傾向があります
  • (繰り返しますが、私が正しく理解していれば)IO in Haskellは、純粋なコンポーネントから命令型の計算を構築し、言語ランタイムに隠された黒魔術によって「実行」されます。インプレースで機能
  • より単純なレベルでは、埋め込まれたミニLISPをCプログラムにGreenspunningすることは同じことと見なすことができます。S式はC関数の呼び出しから構築して、後で実行できます(この最後の式は通常アンチパターンと見なされます)ケース)、実際にインタプリタデータを渡しているときに、C関数に「ラムダ」を渡しているように見せることができます

問題のツールを使用する唯一の方法であるため、すべての場合にアンチパターンではないことは明らかです(ただし、Cで実行すると1つのビートが発生する可能性があります)。それ自体が「グリーンスパニング」や「EDSLの使用」ではないと思います。それよりも一般的で広く適用できるからです。インタープリターパターンではないと思いますが、正しく理解していない可能性があります。計算はホスト言語コードを実行することによって直接構築されます(したがって、コンパイル時に効果的に存在しますが、通常はファーストクラスの言語としては存在しません)文字列または他のランタイムロードデータから解析されるのではなく、コンストラクト)。

すべての場合において、実際にそのアクションをパッケージ化しながら、操作が1つのことを実行しているように見えます(Cであり、+をオーバーロードする代わりにAddを書き出す必要がある場合は、必ずしも説得力があるとは限りません)。後で消費するために。 「計算ビルダー」パターンのようなものですか?しかし、私はその用語が使用されているのを見つけていません。

ここで解決する実際的な問題はありません。名前を付けることができない共通のデザイン要素があるように思われるのは、私を悩ませているだけです。

(質問はもともとStackOverflowに投稿され、手作業で移動されました)

2
Leushenko

あなたが説明しているように見えるのは遅延評価。結果がソースコードに表示されるときではなく、結果が必要なときに実行される計算です。

Haskellでは、これはこれらの計算をモナド抽象化の背後に隠すことによって行われます。 C++では、抽象化は似ていますが、より明示的であり、オーバーロードされた演算子と式テンプレートの背後に部分的に隠されています。

同様に、CでのLISPのような構造の「Greenspunning」の引用例はアンチパターンではなく、データ駆動型の遅延評価DSLであり、実際には、FFIの最も一般的なパターンの1つであるように思われます。 Cには未実行の関数をデータとして構築して渡す手段がないため、LISPおよびSchemeインタープリター(特にECL、Chicken、tinyschemeなど)。

これらのパターンは、ファーストクラスの関数オブジェクトを持つ言語では表示されないことに気付くでしょう。

9
greyfade

これは遅延評価と呼ばれます。これは非常に一般的なパターンです。実際、Cのような言語で&&または||演算子を使用するたびに、2番目のオペランドは必要な場合にのみ評価されます。同様に、if/then/elseでは、ブランチの1つだけが評価されます。

遅延評価にはいくつかの興味深い特性があります。

副作用がない場合、何かを怠惰にすることはプログラムの結果を変えることはできません。 canただし、非終了プログラムを終了させます。たとえば、次のようなものがある場合:

False && infiniteLoop

熱心な評価では、これは無限ループになりますが、遅延評価では、これはFalseを返します。

IOW:遅延評価により、先行評価では作成できないプログラムを作成できます。 Haskellの有名なフィボナッチ数列の例を考えてみましょう。

fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

[これは悪い例です、ところで、それは最適なアルゴリズムの複雑さを持っていないので。]

With副作用ただし、遅延評価により、副作用が発生する順序が変わる場合があります。または、発生しない場合もありますまったく

純粋なプログラムと完全なプログラムの場合、遅延評価と先行評価の変更まったくない、それは単にコンパイラーの最適化の選択になります。 (プログラム全体は常に終了し、熱心評価と遅延評価の唯一の違いは終了です。したがって、プログラム全体では違いはありません。)

6
Jörg W Mittag

これはまったく遅延評価ではありません。それは完全に独立したものです。

Haskellでは、このパターンは通常、コンビネーターと一緒に発生します。ただし、コンビネーターでは、他の形式の計算を模倣する必要はありません。 (私はおそらくそれを何らかの形の「しゃれ」を模倣していると呼ぶでしょう。)

1
Matthias