web-dev-qa-db-ja.com

関数型プログラミングは、「システムをモジュールに分解する際に使用される基準について」(データ非表示)から得られる利点を無視しますか?

システムをモジュールに分解する際に使用される基準について という名前の古典的な記事があります。これは、初めて読んだばかりです。それは私には完全に理にかなっており、おそらくOOPが基にした記事の1つです。その結論:

これらの例を使用して、フローチャートに基づいてシステムをモジュールに分解することはほとんど常に正しくないことを実証しようとしました。 ...各モジュールは、そのような決定を他のモジュールから隠すように設計されています

私の無学で経験の浅い意見では、関数型プログラミングはこの記事とは正反対のアドバイスをしています。私の理解では、関数型プログラミングはデータフローを慣用的にしています。データは関数から関数に渡され、各関数はデータを密接に認識し、その過程で "changeing it" を行います。リッチヒッキーがデータの隠蔽が過大評価されているか、不必要であるかなどについて語ったリッチヒッキーの講演を見たことがあると思いますが、確かに思い出せません。

  1. まず、私の評価が正しいかどうかを知りたいです。 FPパラダイムとこの記事は哲学的に反対ですか?
  2. FP「データの非表示の欠如」をどのように「補正」するのでしょうか?データの非表示を犠牲にしますが、X、Y、Zを獲得します。Xの理由を知りたいのですが。 、Y、Zは、データを隠すよりも有益であると考えられています。
  3. あるいは、彼らが同意しないと仮定すると、おそらくFPはデータの隠蔽が悪いと感じています。もしそうなら、なぜデータの隠蔽が悪いと思うのですか?
  4. 彼らが同意すると仮定して、データ隠蔽のFP実装とは何かを知りたいのですが。これをOOPで見るのは明らかです。クラス外の誰もアクセスできないprivateフィールドを持つことができます。 FPでは、これについての明確なアナロジーはありません。
  5. 他に質問すべきことはあると思いますが、質問すべきかわかりません。それらにもお気軽にお答えください。

更新

私はこれを見つけました ニール・フォードの話 それは非常に関連するスライドを持っています。ここにスクリーンショットを埋め込みます:

enter image description here

27
Daniel Kaplan

あなたが言及する記事は一般にモジュール性についてであり、それは構造化された機能的なオブジェクト指向プログラムにも等しく適用されます。私は以前、大きなOOP=男だった人からその記事を聞いたことがありますが、何かについてOOP特定ではなく、プログラミングに関する記事として読んでいます。関数型プログラミングに関する有名な記事 なぜ関数型プログラミングが重要か であり、結論の最初の文には「このホワイトペーパーでは、モジュール化がプログラミングの成功の鍵であると主張しました。」とあります。 (1)の答えは「いいえ」です。

適切に設計された関数は、必要以上にデータを想定していないため、「データを密接に認識する」という部分は間違っています。 (または、少なくともOOPの場合と同じくらい間違っています。高水準の抽象化で厳密にプログラムし、すべてのパラダイムですべての詳細を永久に無視することはできません。結局、プログラムの一部は実際にデータの具体的な詳細。)

データの非表示はOOP=特定の用語であり、記事で説明されている情報の非表示とは完全に同じではありません。記事での情報の非表示は、行うのが困難または困難であった設計上の決定に関するものです変更される可能性があります。データ形式に関するすべての設計決定が難しいまたは変更される可能性があるわけではありません。また、変更が難しいまたは変更される可能性があるすべての決定がデータ形式に関するものであるとは限りません。個人的には、OOプログラマーはすべてをオブジェクトにしたい場合がありますが、単純なデータ構造で十分な場合もあります。

編集:私は Rich Hickeyへのインタビュー から関連する引用を見つけました。

Fogus:その考えに従います—一部の人々は、Clojureがそのタイプのデータ非表示カプセル化に従事していないという事実に驚いています。データを非表示にすることをやめたのはなぜですか?

ヒッキー:Clojureはプログラミングを抽象化することを強く強調しています。ただし、ある時点で、誰かがデータにアクセスする必要があります。また、「プライベート」の概念がある場合は、対応する特権と信頼の概念が必要です。そして、それは全体のトンの複雑さと少しの価値を追加し、システムに剛性を作成し、そして多くの場合、物事を本来あるべきでない場所に住まわせます。これは、単純な情報がクラスに入れられるときに発生する他の損失に追加されます。データが不変である限り、誰かが変化する可能性のあるものに依存するようになる可能性があることを除いて、アクセスを提供することによってもたらされる可能性のある害はほとんどありません。ええ、そうですね、人々は実生活でそれを常に行っており、物事が変化するとき、彼らは適応します。そして、彼らが合理的であるならば、彼らは将来彼らが適応する必要があるかもしれない変化することができる何かに基づいて彼らが決定をするときを知っています。ですから、それはリスク管理の決定です。プログラマーは自由に作れるべきだと私は思います。抽象化するようにプログラミングしたいという欲求や、実装の詳細との結婚に警戒心がなければ、優れたプログラマーになることはできません。

23
Michael Shaw

...そしておそらくOOPが基にした記事の1つです。

実際にはそうではありませんでしたが、特に、当時彼が論文で説明した最初の基準を使用してシステムを分解するように訓練されていた実務家にとって、それは議論に追加されました。

まず、私の評価が正しいかどうかを知りたいです。 FPパラダイムとこの記事は哲学的に反対ですか?

さらに、私の目には、FPプログラムがどのように見えるかについての説明は、プロシージャや関数を使用する他のどのプログラムとも変わりません。

データは関数から関数に渡され、各関数はデータを密接に認識し、途中で「変更」します。

...exceptは「親密さ」の部分です。なぜなら、親密さを正確に回避するために、抽象データを操作する関数を使用できる(そしてそうすることが多い)からです。したがって、「親密さ」をある程度制御でき、非表示にしたいものにインターフェース(つまり、関数)を設定することで、好きなように調整できます。

したがって、関数型プログラミングを使用して情報を隠すというParnasの基準に従えず、KWICインデックスの実装になり、彼の2番目の実装と同様の先の尖った利点が得られない理由はわかりません。

彼らが同意すると仮定すると、私はデータ隠蔽のFP実装が何であるかを知りたいのです。これをOOPで見るのは明らかです。クラス外の誰もがアクセスできないプライベートフィールドを持つことができます。 FPでは、これについての明確なアナロジーはありません。

データに関する限り、FPを使用してデータの抽象化とデータ型の抽象化を作成できます。これらはいずれも、抽象化として機能を使用して、コンクリート構造とこれらのコンクリート構造の操作を隠します。

[〜#〜]編集[〜#〜]

FPのコンテキストで「データを非表示にする」ことはそれほど有用ではない(またはOOP風(?))とするアサーションの数が増加しています。 SICPのシンプルで明確な例:

システムが有理数を処理する必要があるとします。それらを表現する方法の1つとして、分子と分母の2つの整数のペアまたはリストを使用できます。したがって:

(define my-rat (cons 1 2)) ; here is my 1/2 

データの抽象化を無視すると、おそらくcarcdrを使用して分子と分母が得られます。

(... (car my-rat)) ; do something with the numerator

このアプローチに従って、有理数を操作するシステムのすべての部分は、有理数がconsであることを認識します-それらは、有理数を作成し、リスト演算子を使用してそれらを抽出するcons番号になります。

直面する可能性のある1つの問題は、有理数の形式を減らす必要がある場合です。システム全体で変更が必要になります。また、作成時に削減を決定した場合、合理的な用語の1つにアクセスするときに削減する方が後で、フルスケールの別の変更が得られることがわかります。

もう1つの問題は、仮説的に、それらの代替表現が優先され、cons表現を放棄することにした場合(フルスケールの変更を再度)です。

これらの状況に対処するための正気な努力は、おそらく、インターフェースの背後にある有理数の表現を隠し始めます。最後に、次のような結果になる可能性があります。

  • (make-rat <n> <d>)は、分子が整数<n>であり、分母が整数<d>である有理数を返します。

  • (numer <x>)は、有理数<x>の分子を返します。

  • (denom <x>)は、有理数<x>の分母を返します。

そして、システムはもはや合理的論理が何でできているのかを知ることはありません(そしてもはやそうすべきではありません)。これは、conscarcdrが有理数に固有ではなく、make-ratnumerdenomareであるためです。もちろん、これは簡単にFPシステムになる可能性があります。そのため、「データの非表示」(この場合、データの抽象化、または表現と具体的な構造をカプセル化する取り組み)は、 OO、関数型プログラミングなどのコンテキストに関係なく、広く使用および調査されている関連概念と手法。

そして要点は...彼らがしている「隠蔽の種類」またはカプセル化を区別しようとするかもしれないが(彼らが設計決定、またはデータ構造またはアルゴリズムを隠しているかどうか-手続き型抽象の場合)、 それらのすべては同じテーマを持っています:それらはパルナスが明示した1つ以上のポイントによって動機付けられます。あれは:

  • 変更可能性:必要な変更をローカルで行うことができるか、システム全体に分散できるか。
  • 独立開発:システムの2つの部分をどの程度並行して開発できるか。
  • 理解可能性:システムのどの部分がその部分の1つを理解するために既知である必要があるか。

上記の例はSICPの本から取られたので、本のこの概念の完全な議論と提示のために、私はチェックすることを強くお勧めします 2章 。また、FPのコンテキストで抽象データ型を理解することをお勧めします。これにより、表に他の問題が生じます。

12
Thiago Silva

関数型プログラミングにはデータの非表示がないというあなたの考えは間違っています。データを非表示にする方法は異なります。関数型プログラミングでデータを非表示にする最も一般的な方法の1つは、関数を引数としてとる多態性関数を使用することです。たとえば、この関数

map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs

データの最も外側の構造(つまり、リスト)しか見ることができません。リストに含まれるデータについては何も見ることができず、渡された単一の関数を介してのみデータを操作できます。

引数として渡される関数は、リストに含まれるデータ型のパブリックメソッドに似ています。データを操作する方法は限られていますが、データ型の内部動作は公開されていません。

8
Dirk Holsopple

ここには少し矛盾があります。関数型プログラミングは関数に重点を置いており、多くの場合、プリミティブデータ型に直接作用する関数を備えていますが、オブジェクト指向プログラミングよりもmoreデータが非表示になる傾向があります。

どうですか?ニースについて考えてみてくださいOO基礎となるデータを非表示にするインターフェイス-おそらくコレクション(私はほぼどこにでもあるものを選択しようとしています)。コレクション内のオブジェクトの基礎となるタイプを知る必要がない場合や、コレクションが実装していることがわかっている限り(たとえば、IEnumerable)、コレクションを実装しているオブジェクトのタイプなので、データを非表示にできます。

関数型プログラミングでは、IEnumerableインターフェイスで効果的に機能するが、プリミティブデータ型(または任意のデータ型)で動作する関数を作成する場合があります。しかし、型がIEnumerableメソッドを実装しなかった場合はどうなりますか?ここに鍵があります「インターフェース」の必要な部分を形成する「メソッド」は常に、関数に渡されるパラメーターにすることができます。または、データと関数を組み合わせて、 OOのような方法。

どちらの方法でも、オブジェクト非表示よりもデータ非表示が少なくないことに注意してください。 anyタイプで機能する私の一般的な関数は、明らかにそのタイプのデータにアクセスしていません-これは、一般的な関数にパラメーターとして渡される関数内で発生しますが、一般的な関数は、これらの関数の内部を覗いて見ることはありませんデータ。

したがって、あなたのポイント1に関しては、FPであり、記事が実際に同意しないとは思いません。FPの特徴が隠れていないとは思わない確かに、FPで作成者が好んだ設計を実装することができます。

ポイント4(2と3は、ポイント1について私が言ったことを考えると、答える意味がありません)までは異なります。また、OO言語によっても異なります。多くのプライベートフィールドでは、言語によって強制されるのではなく、慣例によりプライベートです。

5
psr

私はここで手足を三振して、FP OOでの方法とは異なり、この概念は関係がないと言います。

tl; dr;データを非表示にするポイントは、責任が本来あるべき場所に維持されるようにすることであり、知識のないデータを外部のアクターがいじくり回すことはありません。 FPでは、データは式によって生成されます。この方法では、ゲームのルールを完全に変更する合成可能な計算ほど変更可能なプロパティではないため、データをいじることはできません。


私のFPの経験では、確かに取るに足らないものですが、私はOOとの明確なコントラストをよく/一般的なデータモデリングを表すものに見出す傾向があります。

これとは対照的に、OOでは一般に、データを表すために物事をモデル化します。義務的な自動車の例:

[〜#〜] oo [〜#〜]

  • あなたは車のオブジェクトを持っています。それはAC実装などの車の詳細を正しく非表示にします(ベルト駆動ですか、それとも空気圧駆動ですか?消費者は知る必要がないので非表示にします)。
  • この自動車オブジェクトには、自動車に関するすべての事実と、自動車での作業方法を示す多くのプロパティとメソッドがあります。
  • この自動車オブジェクトには、自動車全体の特定の実装をさらに隠す自動車のコンポーネントであるプロパティと、自動車のコンポーネントを交換可能にするデータファクトがあります。

ここで注意する点は、OO形式で物事をモデル化しているときは、物事をデータとして表すことです。プロパティを持つオブジェクトがあり、それらのプロパティの多くは、より多くのプロパティを持つオブジェクトです。あなたはあちこちにいくつかのメソッドをそれらのオブジェクトにアタッチしていますが、それらが実際に行うことは通常、オブジェクトのプロパティをこのように揺らすことであり、これも非常にデータ中心のモデリングです。つまり、データをフォーカスと相互作用するようにモデル化しますデータのすべてのポイントを利用できるように構成して、消費者がデータをこのように変更できるようにします。

[〜#〜] fp [〜#〜]

  • あなたはあなたが行動を説明することを可能にする大量の計算を持っています
  • これらの動作の表現は、車の動作が相互に関連している方法に変換できる方法で関連しています。たとえば、加速/減速する自動車には、同様の方法で互いに反対する2つの動作があります。

OOとFPが常に私に影響を与えることの大きな違いは、データをモデル化する方法の上で述べたとおりです。OO =上記のように、データをデータとしてモデル化します。FPでは、データを計算、式、アルゴリズムとしてモデル化します。これは、事実ではなく、データのアクティビティをモデル化することについてです。基本的なデータについて考えてください。数学でのモデリングでは、OOとは対照的に、モデリングは表現する方法を考え出しています。これとは対照的に、データを生成できるアクティビティを取得する方程式を取得することです。あなたが持っているデータです。つまり、FPとOOの違いはmuchです。

非常に長い間、基本的なFP言語の1つであるLISPは、非常に少量のプリミティブデータ型で動作していました。これは、アプローチがの複雑な表現のモデリングに関するものではないため機能しますシステムの動作を生成および表現する計算と同じくらいにデータ。

FPでコードを書き始めるときは、何かを行うコードを書くことから始めます。OOでコードを書き始めるときのように、何かを記述するモデルを書くことから始めます。 FPは式であることで、物事の実行は非表示になり、OOはデータで記述されることで物事の実行は非表示になります。


手元の質問に戻ります。FPデータの非表示について何と言いますか、それを高く評価しますか、それとも反対しますか?

OOで重要ではないと私は言います。あなたのデータは、干渉されないように隠す必要があるプログラム内の重要な部分です。= In FPシステムの根性と知識は、システムを表現するアルゴリズムと計算にすべて隠されています。これらは、定義により、ほぼ不変です。計算式を変更する唯一の方法は、マクロのようなものですが、それでも突然変異の定義ですそれ以上は操作できない表現そのものです。

5
Jimmy Hoffa

TL; DR:いいえ

FPパラダイムとこの記事は哲学的に同意しませんか?.

いいえ、ありません。関数型プログラミングは宣言型です "コンピュータープログラムの構造と要素を構築するスタイルであり、制御フローを記述せずに計算のロジックを表現します。" フローチャートに従うことなどよりは重要ではありません。フローを独自に発生させるルールを作成します。

手続き型プログラミングは、関数型プログラミングよりもフローチャートのエンコーディングに非常に近いものです。したがって、発生する変換、およびそれらの変換を、フローチャートのフローとまったく同じように、順番に実行されるプロシージャにエンコードします。

手続き型言語は、プログラムの実行を、共有状態を暗黙的に変更する可能性がある命令コマンドのシーケンスとしてモデル化するのに対し、関数型プログラミング言語は、相互にのみ依存する複雑な式の評価として実行をモデル化します引数と戻り値の条件。このため、関数型プログラムはより自由な順序でコードを実行でき、プログラムのさまざまな部分が実行される順序を言語がほとんど制御できない場合があります(たとえば、 Schemeでのプロシージャ呼び出しは任意の順序で実行されます。)

データ非表示

  • 関数型プログラミングには独自のデータ非表示メソッドがあり、たとえば closures と考えます。それは、クロージャーにカプセル化することによってデータを隠すことです。クロージャのみがデータへの参照を持ち、クロージャの外部では参照できないため、フィールドがクローズされたプライベートデータになることは困難です。
  • データを非表示にする理由の1つは、変化するデータを非表示にすることでプログラミングインターフェイスを安定させることです。関数型プログラミングには変化するデータがないため、それほど多くのデータを隠す必要はありません。
3
dietbuddha

まず、この素晴らしい記事へのリンクのおかげで、私はこれまでこれを知りませんでした、そしてそれは私がここ数年コミュニティーの他のソフトウェアデザイナーと話し合っているいくつかのことについていくつかの素晴らしいインプットを与えてくれました。これについての私の意見は次のとおりです。

まず、私の評価が正しいかどうかを知りたいです。 FPパラダイムとこの記事は哲学的に反対ですか?

FPの設計は、データフローに非常に重点を置いています(これは、記事が示唆するほど私見では悪くありません)。これが完全な「不一致」である場合は、議論の余地があります。

FP「データの非表示の欠如」をどのように「補正」するのでしょうか?データの非表示を犠牲にしますが、X、Y、Zを獲得します。Xの理由を知りたいのですが。 、Y、Zは、データを隠すよりも有益であると考えられています。

私見それは補償しません。下記参照。

あるいは、彼らが同意しないと仮定すると、おそらくFPはデータの非表示が悪いと感じています。そうであれば、データの非表示が悪いと思うのはなぜですか?

FPユーザーまたはデザイナーがこのように感じたり考えたりすることはほとんどないと思います。以下を参照してください。

彼らが同意すると仮定して、データ隠蔽のFP実装とは何かを知りたいのですが。これをOOPで見るのは明らかです。クラス外の誰もがアクセスできないプライベートフィールドを持つことができます。 FPでは、これについての明確なアナロジーはありません。

ここにポイントがあります-あなたはおそらくあなたが信じるほど多くのOOP非機能的な方法で実装されたシステムを見てきたOOPは非機能的です。そしてそれは誤解、IMHO OOPとFPは主に直交する概念であり、完全に機能的なOOシステムを構築できるため、 FPの古典的な「オブジェクト」実装は closures を使用して行われます。オブジェクトを機能システムで使用したい場合は、重要な点は、それらを不変に設計することです。

したがって、より大きなシステムを作成するために、IMHOはOOの概念を使用して、記事の「モジュール化2」で説明されている方法とまったく同じように、「FPパス」を離れずにモジュール、クラス、およびオブジェクトを作成できます。お気に入りのモジュールの概念を使用するFP言語、すべてのオブジェクトのみを不変にして、「両方の長所」を使用する。

3
Doc Brown