web-dev-qa-db-ja.com

働く人のためのコンビネーターの説明

コンビネータとは?

「自由変数のない関数または定義」(SOで定義)

または、これについてはどうでしょうか。 John Hughes Arrowsに関する有名な論文によれば、 "コンビネータは、プログラムフラグメントからプログラムフラグメントを構築する関数です"、これは「...コンビネータを使用するプログラマは、すべての詳細を手作業で書くのではなく、必要なプログラムの多くを自動的に構築する」ため有利です。彼は、mapfilterがそのようなコンビネーターの2つの一般的な例であると続けています。

最初の定義に一致するいくつかのコンビネーター:

2番目の定義に一致するいくつかのコンビネーター:

  • 地図
  • フィルタ
  • 折りたたみ/縮小(おそらく)
  • >> =、compose、fmapのいずれか?????

私は最初の定義には興味がありません-それらは本当のプログラムを書くのを助けません(あなたが私が間違っていると私に納得させるなら+1)。 2番目の定義を理解するのを手伝ってください。 map、filter、reduceは有用だと思います。これらにより、より高いレベルでプログラミングできます。ミスが少なく、コードが短く、明確です。以下に、コンビネーターに関する具体的な質問をいくつか示します。

  1. マップ、フィルターなどのコンビネーターのその他の例は何ですか?
  2. プログラミング言語でよく実装されるコンビネーターは何ですか?
  3. コンビネーターはどのように優れたAPIを設計するのに役立ちますか?
  4. 効果的なコンビネーターを設計するにはどうすればよいですか?
  5. 非機能言語(Javaなど)に似ているコンビネーターとは何ですか、またはこれらの言語はコンビネーターの代わりに何を使用しますか?

更新

@Cに感謝します。 A.マッキャン、コンビネーターの理解がやや深まりました。しかし、1つの質問はまだ私にとっての難点です。

コンビネータを多用して書かれた機能プログラムと、書かれていない機能プログラムの違いは何ですか?

答えは、コンビネータが重いバージョンがより短く、より明確で、より一般的であると思われますが、可能であれば、より詳細な議論をお願いします。

また、一般的なプログラミング言語での複雑なコンビネータ(つまり、foldよりも複雑)の例と説明も探しています。

90
Matt Fenwick

私は最初の定義には興味がありません-それらは本当のプログラムを書くのを助けません(あなたが私が間違っていると私に納得させるなら+1)。 2番目の定義を理解してください。 map、filter、reduceは有用だと思います。これらにより、より高いレベルでプログラミングできます。ミスが少なく、コードが短く、明確です。

2つの定義は基本的に同じものです。最初は正式な定義に基づいており、指定する例はprimitive combinators-可能な最小の構成要素です。それらは、より洗練されたコンビネーターを構築できる限り、実際のプログラムを書くのに役立ちます。 SやKなどのコンビネータは、仮想の「コンビナトリアルコンピュータ」の機械語と考えてください。もちろん、実際のコンピューターはそのようには機能しないため、実際には通常、他の方法でバックグラウンドで高レベルの操作を実装しますが、概念的な基盤はこれらの高レベル操作の意味

2つ目の定義は、他の関数をさまざまな方法で結合する高階関数の形式で、より非公式で、より洗練されたコンビネーターの使用に関するものです。基本的なビルディングブロックが上記のプリミティブコンビネータである場合、それらからビルドされるeverythingは高階関数であり、コンビネータでもあることに注意してください。ただし、他のプリミティブが存在する言語では、関数であるかそうでないかを区別します。その場合、コンビネーターは通常、非-で操作するのではなく、一般的な方法で他の関数を操作する関数として定義されます直接機能します。

マップ、フィルターなどのコンビネーターのその他の例は何ですか?

リストするには多すぎます!どちらも、単一の値の動作を記述する関数を、コレクション全体の動作を記述する関数に変換します。また、他の関数を変換するonly関数、たとえば、それらをエンドツーエンドで構成したり、引数を分割および再結合したりすることもできます。シングルステップ操作をコレクションを生成または消費する再帰的操作に変換するコンビネーターを使用できます。または、他のすべての種類の、本当に。

プログラミング言語でよく実装されるコンビネーターは何ですか?

それはかなり異なるでしょう。完全に汎用的なコンビネーターはほとんどなく、ほとんどが上記のプリミティブなコンビネーターであるため、ほとんどの場合、コンビネーターは使用されているデータ構造をある程度認識します(これらのデータ構造が他のコンビネーターから構築されている場合でも)通常、少数の「完全に汎用的な」コンビネーターがあり、その後、誰かが提供することを決めたさまざまな特殊な形式があります。 (適切に一般化されたバージョンの)map、fold、unfoldで、必要なほぼすべてのことを行うのに十分な場合があります。

コンビネーターはどのように優れたAPIを設計するのに役立ちますか?

まさにあなたが言ったように、低レベルの詳細ではなく、高レベルの操作とそれらの相互作用の観点から考えることによって。

コレクションの「for each」スタイルのループの人気を考えてください。これにより、コレクションの列挙の詳細を抽象化できます。ほとんどの場合、これらは単なるマップ/フォールド操作であり、(組み込みの構文ではなく)コンビネーターを作成することにより、2つの既存のループを取得し、複数の方法で直接結合するなどの操作を実行できます。大量のコードをジャグリングするのではなく、コンビネータを適用するだけで、次々に実行します。

効果的なコンビネーターを設計するにはどうすればよいですか?

最初に、プログラムが使用するデータでどのような操作が理にかなっているかを考えます。次に、これらの操作を一般的な方法で有意義に組み合わせる方法と、操作を小さな部分に分割して相互に接続する方法を考えます。主なものは、transformationsおよびoperationsではなく、直接アクション。不透明な方法でいくつかの複雑な機能を実行し、事前に消化された結果を吐き出すだけの関数がある場合、それでできることはあまりありません。最終的な結果は、コンビネータを使用するコードに残します-期待するものではなく、ポイントAからポイントBに行くものが必要ですプロセスの開始または終了。

非機能言語(Javaなど)に似ているコンビネーターとは何ですか、またはこれらの言語はコンビネーターの代わりに何を使用しますか?

あはははは。面白いのは、オブジェクトはそもそも本当に高次のものであるためです-それらはいくつかのデータを持っていますが、多くの操作を実行し、優れたOOPデザインを構成するものもたくさんあります要約すると、「オブジェクトは通常、データ構造ではなくコンビネータのように振る舞うべきです」。

したがって、おそらくここでの最良の答えは、コンビネーターのようなものの代わりに、多くのゲッターおよびセッターメソッドまたはパブリックフィールド、およびいくつかの不透明な定義済みアクションを実行することで主に構成されるロジックを持つクラスを使用することです。

92
C. A. McCann