51

Haskellの型クラスがOCamlで行うことを達成するためのいくつかの方法は何ですか?基本的には、あまりコードを書かずにポリモーフィック関数を書きたいと思っています。ポリモーフィズムを実行する一般的な方法は、関数が現在作業しているタイプであることを示す追加の引数を指定することです。たとえば、intのリストを並べ替えたい場合、追加のコンパレータを関数に渡す必要があります。

type comparison = Lesser | Equal | Greater

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

ソートしたいすべてのタイプのコンパレータ関数を記述せずに、私のタイプが比較可能であることをOCamlに伝える方法はありますか?つまり、私の並べ替え関数は次のようになります。

my_sort : 'a list -> 'a list
4

5 に答える 5

30

それは本当にあなたが何を達成したいかによります。

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)
于 2013-02-18T11:09:43.283 に答える
29

これは、Derek Dreyer、Robert Harper、およびManuelMTChakravartyによる「モジュラー型クラス」で詳細に説明されています。第34回ACMSIGPLANの議事録-プログラミング言語の原則に関するSIGACTシンポジウム、ACM Press、2007年。要約から:

MLモジュールとHaskell型クラスは、プログラム構造化のための非常に効果的なツールであることが証明されています。モジュールは、プログラムコンポーネントの明示的な構成とデータ抽象化の使用を強調します。型クラスは、暗黙のプログラム構築とアドホック多相性を強調します。この論文では、型クラスをモジュールの特定の使用モードと見なすことにより、型クラスプログラミングの暗黙的に型付けされたスタイルが明示的に型付けされたモジュール言語のフレームワーク内でどのようにサポートされるかを示します。このビューは、モジュールと型クラスの調和のとれた統合を提供します。クラス階層や関連する型などの型クラス機能は、モジュール階層や型コンポーネントなどの既存のモジュール言語構造の使用として自然に発生します。加えて、プログラマーは、特定のスコープで型推論によって使用できる型クラスインスタンスを明示的に制御できます。アプローチをハーパーストーンスタイルの精緻化関係として形式化し、実装のガイドとしてサウンドタイプ推論アルゴリズムを提供します。

于 2013-02-18T12:03:58.537 に答える
15

Haskellの型と型クラスとOCamlのモジュールとモジュール型の間の変換を示す本当に素晴らしい記事に出くわしました:http://conway.rutgers.edu/~ccshan/wiki/blog/posts/Translations/

基本的に、@ Thomasが示したように、Haskellの型クラスは、型(型クラスを実装する型)とその型を使用する一連の値を持つOCamlのモジュール型になります。

次に、Haskellの型クラスの「インスタンス」に対応して、モジュール型を実装するOCamlのモジュールがあります。型はインスタンスの型であり、値は型クラスの値の実装です。 。

そして、Haskellでその型クラスによって制約された型を「使用する」関数があるたびに、その関数をOCamlのモジュール内にラップする必要があります。このモジュール(実際にはファンクター)は、使用している型クラスのインスタンスに対応する引数モジュールを取ります。

そして、その関数を使用するたびに、最初にそのファンクターを使用して適切なモジュールを作成し、それに型クラスの適切なインスタンスを渡す必要があります。

HaskellとOCamlのやり方の大きな違いは、Haskellでは、最後の関数を使用すると、コンパイラが型クラスの適切なインスタンスを推測することです一方、OCamlの方法では、ユーザーは使用するインスタンスを明示的に指定する必要があります。

于 2013-02-18T20:34:19.230 に答える
10

モジュールほど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
于 2013-02-18T19:47:49.537 に答える
3

一般に、OCamlは暗黙のパラメータをサポートしていないため、型クラスのインスタンスを明示的に渡すには、ある種の辞書パラメータが必要です。これは、ポリモーフィックレコード、ファーストクラスモジュール、またはオブジェクトの観点から実装できます。モジュールを使用する方法を示すサンプルプロジェクトがあります:https ://github.com/hongchangwu/ocaml-type-classes

于 2016-11-20T20:19:02.653 に答える