通过枚举自动记忆OCaml中的复杂数据类型?

时间:2016-05-02 04:36:34

标签: ocaml memoization

我正在将一个数学描述的算法的实现写入OCaml。我正在努力保持实现的清洁和贴近本文,并且只使用记忆定义这些定义良好的技术来提高性能。

不幸的是,虽然memoization在整数上运行得很好,但对于大型或复杂的数据类型,它仍然可以是O(n)。通过在记忆之前枚举数据类型,可以获得O(1)性能。 例如,我们在下面的示例中看到memo len仍然是O(n),但DroidMemoized.len将是O(1),而DroidMemoizedDroid的替代品1}}。

但是,是否可以自动从DroidMemoized创建Droid?例如,是否有模块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

1 个答案:

答案 0 :(得分:0)

为Functors很容易生成样板,但我能为函数包装器做的最好的事情是使用外部实用程序来解析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";
   }
}

我已将其刷新为Perl脚本以记忆模块:https://github.com/gmatht/joshell/blob/master/scripts/memoize.pl