Подтвердить что ты не робот

Не могли бы вы объяснить мне функторы OCaml?

Возможный дубликат:
В функциональном программировании, что является функтором?

Я мало что знаю о OCaml, я некоторое время изучал F # и вполне понимаю.

Говорят, что F # пропускает модель-функтор, которая присутствует в OCaml. Я попытался выяснить, что такое функтор, но википедия и учебники не очень помогли мне.

Не могли бы вы освежить эту тайну для меня? Спасибо заранее:)

EDIT:

Я поймал суть, спасибо для всех, кто помог мне. Вы можете закрыть вопрос как точный дубликат: В функциональном программировании, что является функтором?

4b9b3361

Ответ 1

Если вы пришли из юниверса ООП, то это, вероятно, помогает думать о модуле, аналогичном статическому классу. Подобно статическим классам .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 # знает, как сравнивать два объекта типа 'a с помощью операторов < и >?

За кулисами он делает что-то вроде этого:

> let gt x y = x > y;;

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

Хорошо, ну что, если у вас есть объект типа Person, который не реализует этот конкретный интерфейс? Что делать, если вы хотите определить функцию сортировки на лету? Один из подходов состоит только в следующем:

    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))

Ответ 2

Функторы - это модули, параметризованные модулями, т.е. отражение от модулей к модулям (обычная функция - отражение от значений до значений, полиморфная функция - отражение от типов к обычным функциям).

См. также ocaml-учебник по модулям.

Примеры в руководстве также полезны.