純粋に機能的な言語はモジュール性をどのように処理しますか?


23

私は、オブジェクト指向のバックグラウンドから来ました。そこでは、クラスを使用して、少なくともオブジェクトを作成するために使用するか、継承で使用できるコードの簡単なリサイクルを可能にする抽象化層を作成することができます。

たとえば、動物のクラスを持つことができ、そこから猫と犬を継承し、すべてが同じ特性を多く継承し、それらのサブクラスから動物の品種または名前を指定できるオブジェクトを作成できますそれの。
または、クラスを使用して、わずかに異なるものを処理または含む同じコードの複数のインスタンスを指定できます。検索ツリーまたは複数の異なるデータベース接続のノードとそうでないもの。

私は最近関数型プログラミングに移行しているので、私は疑問に思い始めて
いました。つまり、クラスとオブジェクトの概念のない言語です。


1
なぜ関数型はクラスを意味しないと思いますか?いくつかの最初のクラスは、LISP- CLOSからのものです 。clojureの名前空間タイプ、またはモジュールhaskellを見てください。

クラスを持っていない関数型言語について言及しましたが、DO
Electric Coffeeの

1
例としてCamlは、姉妹言語であるOCamlがオブジェクトを追加しますが、Caml自体にはオブジェクトがありません。
エレクトリックコーヒー

12
「純粋に機能的な」という用語は、参照の透明性を維持し、言語にオブジェクト指向機能があるかどうかとは無関係な機能言語を指します。
sepp2k

2
ケーキは嘘です、オブジェクト指向でのコードの再利用はFPよりもはるかに困難です。オブジェクト指向が長年にわたってコードの再利用を主張してきたことすべてについて、私はそれが最小限の時間で続くのを見てきました。(間違ったことをしなければならないと言うだけで、私は何年もオブジェクト指向システムを設計し、維持しなければならなかったオブジェクト指向コードをどれだけうまく書いているか、自分の結果の品質を知っています)
ジミー・ホファ

回答:


19

多くの関数型言語にはモジュールシステムがあります。(ちなみに、多くのオブジェクト指向言語も同様です。)しかし、言語がなくても、関数をモジュールとして使用できます。

JavaScriptは良い例です。JavaScriptでは、関数はモジュールの実装とオブジェクト指向のカプセル化の両方に使用されます。JavaScriptの主なインスピレーションであったSchemeには、関数しかありませ。関数は、オブジェクト、モジュール(ラケットではユニットと呼ばれます)、データ構造など、ほとんどすべてを実装するために使用されます。

OTOH、Haskell、およびMLファミリには、明示的なモジュールシステムがあります。

オブジェクト指向は、データの抽象化に関するものです。それでおしまい。モジュラリティ、継承、ポリモーフィズム、可変状態さえも直交の問題です。


8
Oopに関連して、これらの機能の仕組みをもう少し詳しく説明できますか?むしろ単純な概念が存在することを伝えるよりも...
電気コーヒー

サイドノート-モジュールとユニットは、ラケットの2つの異なる構造です-モジュールは名前空間に匹敵し、ユニットは名前空間とオブジェクト指向インターフェースの中間に位置します。ドキュメントでは、違いについてより詳細に説明します
ジャック

@ジャック:ラケットにもと呼ばれる概念があることを知りませんでしたmodule。残念ながら、ラケットにはmoduleモジュールではないという概念と、モジュールではあるが呼び出されないという概念がありますmodule。とにかく、あなたは次のように書いた:「ユニットは名前空間とオブジェクト指向インターフェースの中間にある」。さて、そのようなモジュールの定義ではありませんか?
ヨルグWミットタグ14

モジュールとユニットは、どちらも値にバインドされた名前のグループです。モジュールは、他の特定のバインディングセットに依存関係を持つことができますが、ユニットは、ユニットを使用する他のコードが提供する必要がある一般的なバインディングセットに依存関係を持つことができます。ユニットはバインディングを介してパラメーター化されますが、モジュールはパラメーター化されません。バインディングに依存するモジュールmapとバインディングに依存するユニットmapは、モジュール特定の特定のモジュール参照する必要があるという点で異なりますmapからのようなバインディングをracket/base異なりますが、ユニットの異なるユーザーはユニットに異なる定義を与えることができますmap
ジャック14

4

「関数型言語でモジュール性を実現するにはどうすればよいですか」という2つの質問をしているようです。他の答えや「関数型言語で抽象化を作成するにはどうすればいいですか?」答えます。

オブジェクト指向言語では、「動物」、「メールサーバー」、「庭のフォーク」などの名詞に集中する傾向があります。対照的に、機能言語は動詞を強調します。 、「生産する」など。

そのため、関数型言語の抽象化が物事よりも動詞や操作を優先する傾向があることは驚くことではありません。これを説明しようとするとき、私がいつも手を伸ばす1つの例は構文解析です。関数型言語では、パーサーを作成する良い方法は、文法を指定して解釈することです。インタープリターは、構文解析プロセスを抽象化します。

この別の具体的な例は、私が少し前に取り組んでいたプロジェクトです。Haskellでデータベースを作成していました。最下位レベルで操作を指定するための「埋め込み言語」が1つありました。たとえば、ストレージメディアからデータを読み書きすることができました。最高レベルで操作を指定するための別の「埋め込み言語」がありました。それから私は、本質的にはより高いレベルからより低いレベルに操作を変換するためのインタプリタです。

これは非常に一般的な抽象化形式ですが、関数型言語で使用できるのはこれだけではありません。


4

「関数型プログラミング」はモジュール性の問題に対する広範囲に及ぶ影響を伝えませんが、特定の言語はさまざまな方法で大規模プログラミングに対処します。コードの再利用と抽象化は、コードを再利用するのが難しくなればなるほど、相互作用します。抽象化は別として、再利用性の2つの問題に対処します。

静的に型付けされたOOP言語は従来、名目上のサブタイピングを使用していました。つまり、クラス/モジュール/インターフェイスA向けに設計されたコードは、Bが明示的にAに言及している場合にのみクラス/モジュール/インターフェイスBを処理できます。 A向けに設計されたコードは、BがAのすべてのメソッドやフィールドを持っているときはいつでもBを処理できます。Bは、より一般的なクラス/インターフェイスAが必要になる前に別のチームによって作成できたはずです。たとえば、OCamlでは、構造サブタイプモジュールシステム、OOPのようなオブジェクトシステム、およびその非常にユニークな多相バリアント型に適用されます。

OOPとFP wrtの最も顕著な違い。モジュール性は、OOPのデフォルトの「ユニット」が同じ値のケースでオブジェクトとしてさまざまな操作をバンドルする一方で、FPのデフォルトの「ユニット」は値のさまざまなケースで同じ操作を機能としてバンドルします。FPでは、たとえばモジュールとして操作をまとめることは依然として非常に簡単です。(ところで、HaskellもF#も本格的なMLファミリモジュールシステムを備えていません。)これ式の問題は、すべての値で動作する新しい操作(たとえば、既存のオブジェクトへの新しいメソッドの付加)と値の新しいケースの両方を段階的に追加するタスクですすべての操作がサポートする必要があります(たとえば、同じインターフェイスで新しいクラスを追加する)。以下の最初のRalf Laemmel講義(C#で広範な例があります)で説明したように、

ScalaでのOOPとFPの組み合わせにより、Scalaは最も強力な言語の1つになります。モジュール性。しかし、OCamlは今でも私のお気に入りの言語であり、個人的な主観的な意見では、Scalaには及ばないわけではありません。以下の2つのRalf Laemmel講義では、Haskellの表現問題の解決策について説明します。このソリューションは完全に機能しますが、結果のデータをパラメトリック多型で使用することを難しくすると思います。以下にリンクされているJaques Garrigueの記事で説明されているOCamlの多型バリアントで式の問題を解決することには、この欠点はありません。また、OCamlでの非OOPとOOPモジュールの使用を比較する教科書の章にもリンクしています。

以下は、式問題を拡張するHaskellおよびOCaml固有のリンクです。


2
これらのリソースが何をするのか、そして質問に答える際にこれらを推奨するのはなぜですか?「リンクのみの回答」はStack Exchangeでは歓迎されていません
-gnat

2
編集として、単なるリンクではなく実際の回答を提供しました。
ルクスタフィ

0

実際、OOコードは再利用性がはるかに低く、それは仕様によるものです。OOPの背後にある考え方は、特定のデータの操作を、クラスまたは継承階層の適切な場所にある特定の特権コードに制限することです。これにより、可変性の悪影響が制限されます。データ構造が変更された場合、責任を持つことができるコード内の場所は非常に多くなります。

不変性を使用すると、だれもデータのコピーを変更できないため、特定のデータ構造を誰が操作できるかは気にしません。これにより、既存のデータ構造で機能する新しい関数の作成がはるかに簡単になります。関数を作成し、それらをドメインの観点から適切と思われるモジュールにグループ化するだけです。継承階層のどこに当てはめるか心配する必要はありません。

他の種類のコードの再利用は、既存の機能で動作する新しいデータ構造を作成することです。これは、ジェネリックや型クラスなどの機能を使用して関数型言語で処理されます。たとえば、HaskellのOrd型クラスを使用するsortと、Ordインスタンスを持つ任意の型で関数を使用できます。インスタンスは、まだ存在していなければ簡単に作成できます。

Animal例を挙げて、フィード機能の実装を検討してください。簡単なOOP実装は、Animalオブジェクトのコレクションを維持し、すべてのオブジェクトをループして、各オブジェクトでfeedメソッドを呼び出します。

ただし、詳細を把握すると、事態は複雑になります。Animalオブジェクトは、当然、それが食べる食べ物の種類を知っているし、どのくらいそれが満腹感を感じるために必要です。それはないではない食品が保たれてどこ当然知っているので、どのくらいの、利用可能であるFoodStoreオブジェクトは、ちょうどすべてのの依存関係となっているAnimalいずれかのフィールドとして、Animalオブジェクト、またはのパラメータとして渡されたfeed方法。代わりに、Animalクラスをよりまとまりのある状態に保つためfeed(animal)に、FoodStoreオブジェクトに移動するか、クラスAnimalFeederなどの嫌悪感を作成することができます。

FPでは、aのフィールドがAnimal常にグループ化されたままになる傾向はありません。これは、再利用性に興味深い意味を持ちます。あなたはのリスト持っていると言うAnimalのフィールドが好きで、レコードをnamespecieslocationfood typefood amount、などまたのリスト持っているFoodStoreようなフィールドを持つレコードをlocationfood typefood amount

給餌の最初のステップは、それらの記録リストのそれぞれ(food amount, food type)を、動物の量が負の数であるペアのリストにマッピングすることです。その後、これらのペアを使用してあらゆる種類のことを行う関数を作成できます。たとえば、各タイプの食品の合計を計算できます。これらの関数はAnimalFoodStoreモジュールまたはモジュールに完全に属しているわけではありませんが、両方で高度に再利用できます。

最終的に[(Num A, Eq B)]は、再利用可能でモジュール化された便利な機能を実行する関数の束になりますが、それらをどこに配置するか、グループとして何を呼び出すかを理解するのは困難です。その結果、FPモジュールは分類が難しくなりますが、分類はそれほど重要ではありません。


-1

人気のあるソリューションの1つは、コードをモジュールに分割することです。JavaScriptでコードを実行する方法は次のとおりです。

    media.podcast = (function(name) {
    var fileExtension = 'mp3';        

     function determineFileExtension() {
         console.log('File extension is of type ' + fileExtension);
     }

     return {
         download: function(episode) {
            console.log('Downloading ' + episode + ' of ' + name);
            determineFileExtension();
        }
    }    
}('Astronomy podcast'));

JavaScriptでこのパターンを説明する記事全文離れのようなモジュールを定義する他の方法の数があることから、RequireJSCommonJS、Googleの閉鎖が。もう1つの例はErlangです。ここには、APIとパターンを強制するモジュール動作の両方があり、OOPのインターフェースと同様の役割を果たします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.