Ocaml 在这种情况下我需要一个函子吗?
我在以下代码中使用:Ocaml 在这种情况下我需要一个函子吗?,ocaml,Ocaml,我在以下代码中使用: 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
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 ) ;;
请注意,当您有位字符串{vv:32}
该vv应为Int32值。我想将这个函数推广到不同宽度的位字符串;也就是说,我想创建一个build_data_n函数,其中位字符串将使用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
在这种情况下,函子可以方便地推广这个函数吗?如果可以,我该如何设置它?(如果还有其他不需要函子的方法,也很高兴知道)有几种方法可用。一种是使用函子,类似于以下内容:
(* 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
这些方法中的每一种都可以混合和匹配。您还可以将值包装在变量类型或对象中以获得类似的结果。使用
位字符串{vv:n}
,即使用运行时指定的字段长度,vv
的类型不能依赖于n
,因为它不再是编译时常量,因此,vv
被迫int64
坦白说,我认为你的解决方案太复杂了,无法回答一个潜在的初学者问题。我知道一流的模块是新的、热门的和有趣的,但我们应该首先支持简单性。在这种情况下,如果没有ygrek解释的位串干扰,一个简单的解决方案是将of int
和succ
作为build\u data
函数的参数传递。我觉得很不安的是,您提供了三个包含大量样板文件的解决方案,但不是这一个。@gasche:是的,将of int和succ函数作为参数传入可能是最简单的。。。除了ygrek解释的问题。不过,看到一流的模块解决方案还是很有趣的。那么,你是说如果你对字段长度(上面的n)使用一个变量,那么vv将始终被强制为int64吗?啊,是的,我明白你的意思了:#让我们得到#bitstring v n=bitstring{v:n};;val get_bitstring:int64->int->bitstring.bitstring=