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

Какая ближайшая вещь для Haskell выглядит в OCaml?

Какими способами я могу выполнить то, что классные классы Haskell в OCaml? В принципе, я хочу написать полиморфную функцию, не пишу слишком много кода. Типичным способом полиморфизма является предоставление дополнительного аргумента, указывающего, что функция - это тип, над которым он сейчас работает. Например, допустим, что я хочу отсортировать список ints, я должен передать дополнительный компаратор функции.

type comparison = Lesser | Equal | Greater

my_sort : (a' -> a' -> comparison) -> 'a list -> 'a list

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

my_sort : 'a list -> 'a list
4b9b3361

Ответ 1

Это действительно зависит от того, чего вы хотите достичь.

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

let my_sort l = List.sort Pervasives.compare l

Более общий способ имитации классов классов - использовать функторы:

module type COMPARABLE = sig
  type t
  val compare: t -> t -> int
end

module MySort (C: COMPARABLE) = struct
  let sort l = List.sort C.compare l
end

(* You can now use instantiate the functor *)
module IntAscending = struct
  type t = int
  let compare = (-)
end
module IntDescending = struct
  type t = int
  let compare x y = y - x (* Reverse order *)
end

module SortAsc = MySort(IntAscending)
module SortDesc = MySort(IntDescending)

Ответ 2

Это подробно объясняется в разделе Модульные типы классов" Дереком Драйером, Робертом Харпером и Мануэлем М. Т. Чакраварти. В материалах 34-го ежегодного симпозиума ACM SIGPLAN-SIGACT по принципам языков программирования, ACM Press, 2007. Из реферата:

Модули ML и классы типа Haskell оказались очень эффективными инструментами для структурирования программ. Модули подчеркивают явную конфигурацию компонентов программы и использование абстракции данных. Типовые классы подчеркивают неявное построение программы и специальный полиморфизм. В этой статье мы покажем, как неявно типизированный стиль программирования классов типов может поддерживаться в рамках явно типизированного языка модуля, рассматривая классы типов как особый способ использования модулей. Это представление обеспечивает гармоничную интеграцию модулей и классов типов, где функции класса классов, такие как иерархии классов и связанные с ними типы, естественно возникают как использование существующих конструкций на языке модулей, таких как иерархии модулей и компоненты типа. Кроме того, у программистов есть явный контроль над тем, какие экземпляры класса классов доступны для использования по типу вывода в заданной области. Мы формализуем наш подход как отношение разработки в стиле Harper-Stone и предоставляем алгоритм вывода типа звука как руководство к реализации.

Ответ 3

Я столкнулся с действительно хорошей статьей, демонстрирующей перевод классов типов и типов в Haskell, а также модулей и типов модулей в OCaml: http://conway.rutgers.edu/~ccshan/wiki/blog/posts/Translations/

В основном, как показал @Thomas, классы классов в Haskell становятся типами модулей в OCaml с типом (тип, реализующим класс типа) и связью значений с использованием этого типа.

Затем, соответствуя "экземпляру" класса type в Haskell, у вас есть модуль в OCaml, который реализует тип модуля, причем тип является типом экземпляра, а значения представляют собой реализацию значений в тип класса.

И затем, каждый раз, когда у вас есть функция, которая "использует" тип, ограниченный этим типом класса в Haskell, вам необходимо обернуть эту функцию внутри модуля в OCaml. Этот модуль (фактически, функтор) примет модуль аргумента, который соответствует экземпляру используемого типа.

И каждый раз, когда вы используете эту функцию, вам нужно сначала создать соответствующий модуль с помощью этого функтора и передать ему правильный экземпляр класса типа.

Вы заметите, что большая разница в способах Haskell и OCaml заключается в том, что в Haskell, когда вы используете эту последнюю функцию, компилятор выдает соответствующий экземпляр класса type для вас; в то время как с помощью OCaml для этого пользователь должен явно указать используемый экземпляр.

Ответ 4

Хотя не так близко к Haskell как модули, типы классов по иерархии классов объектов неясны.

См. определения типа класса.

Обновление: рабочий пример:

type comparison = Lesser | Equal | Greater

class type comparable = object ('a)
  method compareTo: 'a -> comparison
end ;;

class type textualizable = object
  method toString: string
end ;;

(* this corresponds in Haskell to a multiparameter type class *)
class type ['b] printable = object ('a)
  constraint 'b = #textualizable         
  method printWithPrefix: 'b -> unit
end ;;

class type ['b] comparableAndPrintable = object ('a)
  inherit comparable
  inherit ['b] printable
end ;;

(* -------------- *)

class textile (str_init:string): textualizable = object
   val str = str_init
   method toString = str
end ;;

class comparableAndPrintableImpl1 (x_init: int) = object (this:'a)

  constraint 'a = 'b #comparableAndPrintable    (* interface implementation requirement *)
  constraint 'b = textualizable (* concrete type parameter *)

  val x = x_init
  method getx = x
  method compareTo (that:'a) = let r = this#getx - that#getx in
                               match r with
                               | 0 -> Equal
                               | _ when r < 0 -> Lesser
                               | _ -> Greater

  method printWithPrefix (pref: 'b)  = Printf.printf "%s %d\n" pref#toString x
end ;;

let boxSort (pivot: #comparable) (lows, equals, highs) (x: #comparable) =
      match x#compareTo pivot with
                    | Lesser -> x :: lows, equals, highs
                    | Equal -> lows, x :: equals, highs
                    | Greater -> lows, equals, x :: highs
      ;;

let rec qsort (li : #comparable list) =
      match li with
          [] | [_] -> li
          | [a;b] -> (match a#compareTo b with
                     Lesser | Equal -> [a;b]
                     | Greater -> [b;a]
                     )
          | x :: xs -> let (lows, equals, highs) = List.fold_left (boxSort x) ([], [], []) xs in
                       qsort lows @ (x :: equals) @ qsort highs
  ;;


let print_myList (prefix: 'a) (li: 'a #printable list) =
    let print_it it = it#printWithPrefix prefix in
    print_endline "\nlist: " ;
    List.iter print_it li
    ;;

let intlist (lfrom: int) (lto: int) =
   let open BatLazyList in
   to_list (range lfrom lto)              (* lazy range generator from BatLazyList *)
   ;;

let myComparableAndPrintableList =
  List.map (new comparableAndPrintableImpl1) (List.rev (intlist 1 5))
  ;;

let myprefix = new textile "x ="

let sortAndPrint (li: 'a #comparableAndPrintable list) =
   let sorted = qsort li in
   print_myList myprefix li ;
   print_myList myprefix sorted
   ;;

sortAndPrint myComparableAndPrintableList ;;

компиляция и ссылка:

ocamlfind ocamlc -package batteries -linkpkg test.ml -o test

Ответ 5

В общем, поскольку OCaml не поддерживает неявные параметры, вам нужен какой-то параметр словаря для передачи в экземплярах класса типа явно. Это может быть реализовано с точки зрения полиморфных записей, первоклассных модулей или объектов. У меня есть пример проекта, показывающий способ использования модулей: https://github.com/hongchangwu/ocaml-type-classes