18

重複の可能性:
関数型プログラミングでは、ファンクターとは何ですか?

私は OCaml についてあまり知りませんが、F# についてはしばらく勉強しており、よく理解しています。

彼らは、F# には OCaml に存在するファンクター モデルが欠けていると言っています。ファンクターが正確に何であるかを理解しようとしましたが、ウィキペディアとチュートリアルはあまり役に立ちませんでした。

その謎を解明していただけませんか?前もって感謝します :)

編集:

私は要点をつかみました。私を助けてくれたすべての人に感謝します。次の正確な複製として質問を閉じることができます:関数型プログラミングでは、ファンクターとは何ですか?

4

3 に答える 3

33

OOP ユニバースの出身であれば、モジュールを静的クラスに類似したものと考えると役立つでしょう。.NET 静的クラスと同様に、OCaml モジュールにはコンストラクターがあります。.NET とは異なり、OCaml モジュールはコンストラクターでパラメーターを受け入れることができます。ファンクターは、モジュール コンストラクターに渡すオブジェクトの恐ろしく聞こえる名前です。

したがって、バイナリ ツリーの標準的な例を使用すると、通常は次のように F# で記述します。

type 'a tree =
    | Nil
    | Node of 'a tree * 'a * 'a tree

module Tree =
    let rec insert v = function
        | Nil -> Node(Nil, v, Nil)
        | Node(l, x, r) ->
            if v < x then Node(insert v l, x, r)
            elif v > x then Node(l, x, insert v r)
            else Node(l, x, r)

元気でダンディ。しかし、F# はどのようにしてand演算子'aを使用して型の 2 つのオブジェクトを比較する方法を知っているのでしょうか?<>

舞台裏では、次のようなことを行っています。

> let gt x y = x > y;;

val gt : 'a -> 'a -> bool when 'a : comparison

Personでは、その特定のインターフェイスを実装していないタイプのオブジェクトがある場合はどうでしょうか? その場で並べ替え関数を定義したい場合はどうしますか? 1 つのアプローチは、次のように比較子を渡すことです。

    let rec insert comparer v = function
        | Nil -> Node(Nil, v, Nil)
        | Node(l, x, r) ->
            if comparer v x = 1 then Node(insert v l, x, r)
            elif comparer v x = -1 then Node(l, x, insert v r)
            else Node(l, x, r)

それは機能しますが、挿入、検索、削除などのツリー操作用のモジュールを作成している場合、クライアントは何かを呼び出すたびに順序付け関数を渡す必要があります。

F# がファンクターをサポートしている場合、その仮想構文は次のようになります。

type 'a Comparer =
    abstract Gt : 'a -> 'a -> bool
    abstract Lt : 'a -> 'a -> bool
    abstract Eq : 'a -> 'a -> bool

module Tree (comparer : 'a Comparer) =
    let rec insert v = function
        | Nil -> Node(Nil, v, Nil)
        | Node(l, x, r) ->
            if comparer.Lt v x then Node(insert v l, x, r)
            elif comparer.Gt v x then Node(l, x, insert v r)
            else Node(l, x, r)

まだ仮想的な構文では、次のようにモジュールを作成します。

module PersonTree = Tree (new Comparer<Person>
    {
        member this.Lt x y = x.LastName < y.LastName
        member this.Gt x y = x.LastName > y.LastName
        member this.Eq x y = x.LastName = y.LastName
    })

let people = PersonTree.insert 1 Nil

残念ながら、F# はファンクターをサポートしていないため、厄介な回避策に頼る必要があります。上記のシナリオでは、ほとんどの場合、「ファンクター」をいくつかの補助ヘルパー関数と共にデータ構造に格納して、正しくコピーされるようにします。

type 'a Tree =
    | Nil of 'a -> 'a -> int
    | Node of 'a -> 'a -> int * 'a tree * 'a * 'a tree

module Tree =
    let comparer = function
        | Nil(f) -> f
        | Node(f, _, _, _) -> f

    let empty f = Nil(f)

    let make (l, x, r) =
        let f = comparer l
        Node(f, l, x, r)

    let rec insert v = function
        | Nil(_) -> make(Nil, v, Nil)
        | Node(f, l, x, r) ->
            if f v x = -1 then make(insert v l, x, r)
            elif f v x = 1 then make(l, x, insert v r)
            else make(l, x, r)

let people = Tree.empty (function x y -> x.LastName.CompareTo(y.LastName))
于 2010-03-03T18:52:43.327 に答える
12

ファンクタは、モジュールによってパラメータ化されたモジュールです。つまり、モジュールからモジュールへのリフレクションです (通常の関数は値から値へのリフレクションであり、ポリモーフィック関数は型から通常の関数へのリフレクションです)。

モジュールの ocaml-tutorialも参照してください。

マニュアルの例も役に立ちます。

于 2010-03-03T10:18:00.683 に答える
2

ocaml コースでこのデータ構造を確認してください。

http://www.cs.cornell.edu/Courses/cs3110/2009fa/lecturenotes.asp

ファンクター講義: http://www.cs.cornell.edu/Courses/cs3110/2009fa/lectures/lec10.html

ファンクターを使用したスプレイ ツリーの実装: http://www.cs.cornell.edu/Courses/cs3110/2009fa/recitations/rec-splay.html

于 2010-03-03T16:33:22.967 に答える