2010-03-03 3 views
15

Можно создать дубликат:
In Functional Programming, what is a functor?Не могли бы вы объяснить мне функторы OCaml?

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

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

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

EDIT:

Я поймал точку, ТНХ всем, кто помог мне. Вы можете закрыть вопрос как точный дубликат: In Functional Programming, what is a functor?

+0

Я не F # ни OCaml гуру, так что я выиграл «Я делаю это как официальный ответ, но я думаю, что http://blog.matthewdoig.com/?p=152 может немного помочь вам в объяснении функторов и о том, как F # обходит их отсутствие. –

+0

Я сначала прочитал эту статью, также есть blog.matthewdoig.com/?p=155. Я нахожусь на полпути к пониманию этой вещи :) – Bubba88

ответ

12

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

См. Также ocaml-tutorial on modules.

Examples in the manual также полезны.

+0

Я был на 10 секунд позже :-) Я не специалист, и я понял это объяснение. – yogsototh

+2

Это хорошее объяснение того, что функторы OCaml * являются *, и то, что они * хороши для *, - это программирование общих структур данных (см. Реализацию Set в стандартной библиотеке OCaml, это, пожалуй, самый простой пример функтора) и обычно предлагая эффективное, статически проверенное по типу альтернативное решение многих проблем, которые вы также можете решить с помощью объектно-ориентированного программирования. –

+0

Желаю, чтобы мне повезло) .. Итак, если я правильно понимаю: функторы - это способ создания новых модулей путем параметризации существующих модулей, таких как 'Set'? – Bubba88

29

Если вы приехали из вселенной ООП, то это, вероятно, помогает думать о модуле, аналогичном статическому классу. Подобно статическим классам .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 # Безразлично 't поддерживающие функторы, поэтому вам придется отказаться от некоторых запутанных обходных решений. Для выше сценария, я почти всегда хранить «функтор» в моей структуре данных с некоторыми добавочными вспомогательными функциями, чтобы убедиться, что он получает скопирован вокруг правильно:

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

Благодарим вас за этот полезный пример. Вам удалось сделать это без строки кода Ocaml, huh)) – Bubba88

+4

Как это отличается от приема экземпляра IEqualityComparer, например, в конструкторе? Он может быть реализован ad-hoc с использованием объектных выражений. – Daniel

+6

@ Даниэль: это в основном точка. Функтор OCaml в основном такой же, как передача какого-либо объекта в конструктор модуля. Но так как F # modules == Статические классы .NET и .NET-конструкторы .NET не принимают параметры в своих конструкторах, вам нужно пройти через обручи, чтобы получить такую ​​же функциональность. – Juliet

Смежные вопросы