这是我需要一个仿函数的情况吗?

时间:2011-10-03 20:14:24

标签: ocaml

我正在使用以下代码中的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 }时 该vv应该是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的值,它将是:{ {1}}

这是一个仿函数会派上用手来概括这个函数的情况吗?如果是这样,我该如何设置它? (如果有其他方法可以做到这一点,不需要仿函数,那也很好知道)

2 个答案:

答案 0 :(得分: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 :(得分:2)

使用BITSTRING { vv : n },即使用运行时指定的字段长度,vv的类型不能依赖n,因为它不再是编译时常量,所以{{1} }被迫vv