2016-05-02 9 views
0

私はOCamlに数学的に記述されたアルゴリズムの実装を書いています。私は実装をきれいにして紙に近づけようとしており、パフォーマンスを改善するために暗記のような明確なテクニックしか使用していません。列挙によるOCamlの複雑なデータ型の自動的なメモ帳化?

残念ながら、memoizationは整数ではうまく機能しますが、大規模または複雑なデータ型の場合でもO(n)になります。メモの前にデータ型を列挙してO(1)のパフォーマンスを得ることは可能です。 たとえば、memo lenはまだO(n)になりますが、DroidMemoized.lenはO(1)になり、DroidMemoizedDroidの代わりとなります。

DroidMemoizedDroidから自動的に作成することはできますか?たとえば、モジュールEnumMemoは、let DroidMemoized = EnumMemo.Make(Droid)と書くことができますか?

module Droid = struct 
     type t = string 
     let empty = "" 
     let beep x = x^" notdroids" 
     let boop x = x^" lookingfor" 
     let len x = String.length x 
end 

let memo f = 
    let m = Hashtbl.create 9 in 
    fun x -> 
     try Hashtbl.find m x 
     with Not_found -> 
     let y = f x in 
      Hashtbl.add m x y; y 

module DroidMemoized = struct 
     (* Boilerplate *) 
     let to_id_h : (Droid.t, int) Hashtbl.t = Hashtbl.create 9 
     let from_id_h : (int, Droid.t) Hashtbl.t = Hashtbl.create 9 (*or use array*) 
     let size = ref 0 
     let from_id i = (Hashtbl.find from_id_h i) 
     let to_id (x :Droid.t) : int = 
       if  Hashtbl.mem to_id_h x 
       then Hashtbl.find to_id_h x 
       else (size := (!size)+1; 
         Hashtbl.add to_id_h x (!size); 
         Hashtbl.add from_id_h (!size) x; 
         !size) 
     (* Function wrappers *) 
     let empty = to_id Droid.empty 
     let beep = memo (fun x -> to_id (Droid.beep (from_id x))) 
     let boop = memo (fun x -> to_id (Droid.boop (from_id x))) 
     let len = memo (fun x ->  (Droid.len (from_id x))) 
end 
+0

なぜ '〜O(n個のログ)' '(1)O'でHashtblではありませんか? –

+0

さて、O(1)は良いハッシュ関数を持つ平均的なケースで、O(n)最悪のケースでは、赤い黒のツリーでO(log n)最悪のケースを得ることができます。これらの詳細は質問にあまり関係しないので、私はO(1)に変更します。 – gmatht

答えて

0

ボイラープレートはファンクタのために生成することは容易であるが、私は関数ラッパーのために行うことができる最高の例えば、OCamlのシグネチャを解析する外部のユーティリティを使用しています

#!/usr/bin/env perl 
@signature=`ocaml < droid.ml`; 
our $t; 
foreach(@signature) { 
    if (/type t = (\w+)/ ){ 
     $t=$1; 
    } elsif (/val (\w+) : (\w+)$/){ 
     print "let $1 = " . 
     (($2 eq $t) ? " to_id " : "") . 
     "(Droid.$1)\n"; 
    } elsif (/val (\w+) : (\w+) -> (\w+)$/){ 
     print "let $1 = " . 
     (($3 eq "unit") ? "(" : "memo (") . 
     " fun x -> " . 
     (($3 eq $t) ? "to_id (" : "(") . 
     (($2 eq $t) ? " from_id" : "") . 
     " (Droid.$1 x))\n"; 
    } 
} 

私はモジュールをmemoizeするPerlスクリプトにこれをブラッシュアップしている:https://github.com/gmatht/joshell/blob/master/scripts/memoize.pl

+0

OCamlでより多くの経験を積んだ人が、より良い答えをすれば、Ocamlのやり方がきれいになります。私は自分の答えを受け入れません。 – gmatht

関連する問題