2011-10-03 53 views
2

我在下面的代码使用Bitstring module这是我需要一个仿函数的情况吗?

let build_data_32 v wid = 
    let num = wid/32 in 
    let v' = Int32.of_int(v) in 
    let rec aux lst vv w = match w with 
    0 -> lst 
    | _ -> (BITSTRING { vv : 32 }) :: (aux lst (Int32.succ vv) (w-1)) in 
    Bitstring.concat (aux [] v' num) ;; 

需要注意的是,当你有BITSTRING { vv : 32 } 该节有望成为一个Int32值。我想推广这个函数来处理不同宽度的位串;即,我想创建一个build_data_n函数,其中bitstring将被构造为BITSTRING { vv : n }

但是,这里的问题是,如果n小于32,那么以上使用的succ函数将只是int类型的succ函数。如果是大于32这将是Int64.succ同样的问题,在上面的线let v' = Int32.of_int(v) in - 当值小于32,将其配置为:let v' = v in,而对于值大于32这将是:let v' = Int64.of_int(v) in

这是一个情况下,一个函子会派上用场来推广这个功能,如果是的话,我会如何设置它? (如果还有其他方法可以做到这一点,不需要函子,那也很好)

回答

2

随着BITSTRING { vv : n },即,使用运行时指定的字段长度,vv类型可以不依赖于n,因为它不是在编译时间常数了,所以vv被迫int64

+0

那么你是说如果你使用一个字段长度变量(n),那么vv总是会被强制为一个int64? – aneccodeal

+0

啊,是的,我明白你在说什么了:#let get_bitstring v n = BITSTRING {v:n} ;; val get_bitstring:int64 - > int - > Bitstring.bitstring = aneccodeal

4

有几种方法可用。一种是使用一个仿函数,类似于以下内容:

(* The signature a module needs to match for use below *) 
module type S = sig 
    type t 
    val succ : t -> t 
    val of_int : int -> t 
end 

(* The functor *) 
module Make(M : S) = struct 
    (* You could "open M" here if you wanted to save some typing *) 
    let build_data v = 
    M.succ (M.of_int v) 
end 

(* Making modules with the functor *) 
module Implementation32 = Make(Int32) 
module Implementation64 = Make(Int64) 

let foo32 = Implementation32.build_data 12 
let foo64 = Implementation64.build_data 12 

另一种是包装你的数据类型的记录:

(* A record to hold the relevant functions *) 
type 'a wrapper_t = { x : 'a; succ : 'a -> 'a } 

(* Use values of type 'a wrapper_t in *) 
let build_data v = 
    v.succ v.x 

(* Helper function to create 'a wrapper_t values *) 
let make_int32_wrapper x = { x = Int32.of_int x; succ = Int32.succ } 
let make_int64_wrapper x = { x = Int64.of_int x; succ = Int64.succ } 

(* Do something with a wrapped int32 *) 
let foo32 = build_data (make_int32_wrapper 12) 
let foo64 = build_data (make_int64_wrapper 12) 

最后,如果你正在使用的OCaml 3.12.0或更高版本,你可以使用一流的模块:

(* You can use the module type S from the first example here *) 

let build_data (type s) m x = 
    let module M = (val m : S with type t = s) in 
    M.succ x 

let int32_s = (module Int32 : S with type t = Int32.t) 
let int64_s = (module Int64 : S with type t = Int64.t) 

let foo32 = build_data int32_s 12l 
let foo64 = build_data int64_s 12L 

这些方法可以混合和匹配。您也可以将您的值包装在变体类型或对象中以获得相似的结果。

+1

坦率地说,我认为你的解决方案对于回答潜在的初学者问题来说太复杂了。我知道一流的模块是新的,热门和有趣的,但我们应该首先倾向于简单。在这种情况下,如果不存在由ygrek解释的BITSTRING干扰,一个简单的解决方案将传递'of_int'和'succ'作为'build_data'函数的参数。我发现你提供三种解决方案有很多样板,但不是这个。 – gasche

+0

@gasche:是的,通过参数传递of_int和succ函数可能是最简单的...除了ygrek解释的问题。不过,看到一流的模块解决方案很有意思。 – aneccodeal

相关问题