16

私はOCamlのファンクターを見ています。C++//のいわゆる汎用オブジェクトとまったく同じように見えC#ますJava。今のところJavaの型の消去を無視し、C ++テンプレートの実装の詳細を無視すると(言語機能に興味があります)、ファンクターはジェネリックスとまったく同じです。私がそれを正しく理解していれば、ファンクターはあなたが提供するタイプからの新しい関数のセットをあなたに与えるので、例えば

List<MyClass>.GetType() != List<MyOtherClass>.GetType()

しかし、OCamlを大まかに書き直すことができます

#module Set =
   functor (Elt: ORDERED_TYPE) ->
     struct
       type element = Elt.t
       type set = element list
       let empty = []
       let rec add x s =
         match s with
           [] -> [x]
         | hd::tl ->
            match Elt.compare x hd with
              Equal   -> s         (* x is already in s *)
            | Less    -> x :: s    (* x is smaller than all elements of s *)
            | Greater -> hd :: add x tl
       let rec member x s =
         match s with
           [] -> false
         | hd::tl ->
             match Elt.compare x hd with
               Equal   -> true     (* x belongs to s *)
             | Less    -> false    (* x is smaller than all elements of s *)
             | Greater -> member x tl
     end;;

の中へC#

class Set<T> where T : ISortable
{
    private List<T> l = new List<T>();
    static public Set<T> empty = new Set<T>();
    public bool IsMember(T x) {return l.IndexOf(x) > -1;}
    public void Add(T x) {l.Add(x);}
}

確かに、ファンクターはに影響を与えるため、わずかな違いがあります(これは、の名前空間Moduleと同様に、関数と値の定義の集まりにすぎません)。C#

しかし、それだけですか?ファンクターは単に名前空間に適用されるジェネリックですか?または、私が見逃しているファンクターとジェネリックの間に重要な違いはありますか?

ファンクターが単なる名前空間のジェネリックであるとしても、そのアプローチの重要な利点は何ですか?クラスは、ネストされたクラスを使用してアドホック名前空間として使用することもできます。

4

4 に答える 4

6

しかし、それだけですか?ファンクターは単に名前空間に適用されるジェネリックですか?

はい、ファンクターを「ジェネリックを持つ名前空間」として扱うことができると思います。それ自体は、C ++では非常に歓迎されます。C++では、すべての静的メンバーを持つクラスを使用するしかありませんが、すぐに醜くなります。C ++テンプレートと比較すると、大きな利点の1つは、モジュールパラメーターの明示的な署名です(これは、C ++ 0xの概念になる可能性があると私は信じていますが、おっと)。

また、モジュールは名前空間とはまったく異なります(複数の構造署名、抽象型、プライベート型を考慮してください)。

ファンクターが単なる名前空間のジェネリックであるとしても、そのアプローチの重要な利点は何ですか?クラスは、ネストされたクラスを使用してアドホック名前空間として使用することもできます。

重要な資格があるかどうかはわかりませんが、クラスの使用が明示的に修飾されている間は、名前空間を開くことができます。

全体として、ファンクターだけの明らかな「重要な利点」はないと思います。これは、コードのモジュール化(MLスタイル)とは異なるアプローチであり、コア言語にうまく適合します。言語とは別にモジュールシステムを比較することが大いに意味があるかどうかわからない。

PS C ++テンプレートとC#ジェネリックもまったく異なるため、全体として比較すると少し奇妙に感じます。

于 2009-09-25T10:10:34.770 に答える
5

私がそれを正しく理解していれば、ファンクターはあなたが提供する型から新しい関数のセットを提供します

より一般的には、ファンクターはモジュールをモジュールにマップします。あなたの例は、署名にSet準拠するモジュールをセットを実装するモジュールにマップします。ORDERED_TYPE署名にはORDERED_TYPE型と比較関数が必要です。したがって、C# は、比較関数ではなく型に対してのみセットをパラメーター化するため、同等ではありません。したがって、C# は要素の型ごとに 1 つのセット型しか実装できませんが、ファンクタは要素モジュールごとに多数のセット モジュールを (たとえば昇順と降順で) 実装できます。

ファンクターが単なる名前空間の総称であるとしても、そのアプローチの重要な利点は何ですか?

高次モジュール システムの主な利点の 1 つは、インターフェイスを徐々に改良できることです。OOP では、すべてが公開または非公開です (または、保護または内部などの場合もあります)。モジュールを使用すると、モジュールの署名を意のままに徐々に改良して、モジュールの内部により近いパブリックアクセスを提供し、コードのその部分から離れるにつれてモジュールを抽象化することができます。かなりのメリットだと思います。

OOP と比較して高次モジュール システムが優れている 2 つの例は、相互にデータ構造の実装をパラメーター化することと、拡張可能なグラフ ライブラリを構築することです。他のデータ構造に対してパラメータ化されたデータ構造の例については、 Chris Okasaki の博士論文の「Structural abstraction」のセクションを参照してください。たとえば、キュ​​ーをカテナブル リストに変換するファンクタです。ファンクタを使用した拡張可能で再利用可能なグラフ アルゴリズムの例については、OCaml の優れた ocamlgraph ライブラリと論文Designing a Generic Graph Library using ML Functors を参照してください。

クラスは、ネストされたクラスを使用してアドホック名前空間として使用することもできます。

C# では、他のクラスに対してクラスをパラメーター化することはできません。C++ では、テンプレートを介して渡されたクラスからの継承など、いくつかのことができます。

また、ファンクターをカリー化することもできます。

于 2009-10-18T22:35:24.117 に答える
2

SML のファンクターは生成的であるため、プログラムのある時点でファンクターのアプリケーションによって生成される抽象型は、別の時点で同じアプリケーション (つまり、同じファンクター、同じ引数) によって生成される抽象型と同じではありません。

たとえば、次のようになります。

structure IntMap1 = MakeMap(Int)
(* ... some other file in some other persons code: *)
structure IntMap2 = MakeMap(Int)

IntMap1.t は IntMap2.t とは異なる抽象型であるため、IntMap1 の関数によって生成されたマップを IntMap2 の関数で使用することはできません。

実際には、これは、ライブラリに IntMap.t を生成する関数がある場合、ライブラリの一部として IntMap 構造も提供する必要があることを意味し、ライブラリのユーザーが自分の (または別のライブラリ) IntMap を使用したい場合は、あなたの IntMap から彼の IntMap に値を変換します - それらはすでに構造的に同等ですが。

別の方法は、ライブラリをファンクター自体にし、ライブラリのユーザーが選択した IntMap でそのファンクターを適用することを要求することです。これにより、ライブラリのユーザーは理想よりも多くの作業を行う必要があります。特に、ライブラリが IntMap だけでなく、他の種類の Map やさまざまな Set なども使用している場合。

ジェネリック、OTOH を使用すると、Map を生成するライブラリを作成し、その値を Map を使用する他のライブラリ関数と連携させることが非常に簡単になります。

于 2011-12-11T15:13:16.727 に答える
1

OCaml はファンクターに対して異なる意味を持っているため、問題の解決に役立つソースを見つけました。

http://books.google.de/books?id=lfTv3iU0p8sC&pg=PA160&lpg=PA160&dq=ocaml+functor&source=bl&ots=vu0sdIB3ja&sig=OhGGcBdaIUR-3-UU05W1VoXQPKc&hl=de&ei=u2e8SqqCNI7R-Qa43IHSCw&sa=res&oict=本onepage&q=ocaml%20functor&f=false

それでも、同じ単語が異なる概念に使用されていると混乱します。


OCaml に別の意味があるかどうかはわかりませんが、通常、Functor は「関数オブジェクト」です (こちらを参照してください: http://en.wikipedia.org/wiki/Function_object )。これはジェネリックとはまったく異なります (こちらを参照してください: http://en.wikipedia.org/wiki/Generic_programming )

関数オブジェクトは、関数として使用できるオブジェクトです。ジェネリックは、オブジェクトをパラメーター化する方法です。ジェネリックは、継承 (オブジェクトを特殊化する) とは一種の直交関係にあります。ジェネリックは型安全性を導入し、キャストの必要性を減らします。ファンクターは、改良された関数ポインターです。

于 2009-09-25T06:42:59.863 に答える