我正在尝试在 OCaml [randlist len max] 中创建一个程序,它将生成一个长度为 len 且整数小于 max 的 int 列表。
我想知道以下代码有什么问题:
let randlist dolzina maksimum =
let rec aux dolz maks acc =
match (List.length acc) with
| dolz -> acc
| _ -> aux dolz maks ((Random.int maks) :: acc)
in
aux dolzina maksimum []
这总是返回一个空列表,我不明白为什么。
另一件让我困惑的事情是以下代码出了什么问题:
let randlist dolzina maksimum =
Random.self_init ()
let rec aux dolz maks acc =
match (List.length acc) with
| dolz -> acc
| _ -> aux dolz maks ((Random.int maks) :: acc)
in
aux dolzina maksimum []
一旦我添加 Random.self init (),整个代码就会崩溃。 Random.self_init 到底有什么作用,何时以及如何使用它?
您使用
match
就好像它要比较两个整数值,但这不是它的工作原理。本场比赛:
Match List.length acc with
| dolz -> ...
将始终匹配第一个案例。名称
dolz
是一个与列表长度绑定的新变量。 dolz
的外部定义与此处无关,模式引入了 new 名称。
如果你想比较两个整数值,你应该使用
if
:
if List.length acc = dolz then
...
else
...
模式匹配将与模式匹配的值解构为更小的部分,它不测试相等性。换句话说,你的第一个案例
match List.length acc with
| dolz -> acc
读取:获取
List.length acc
返回的值,将其命名为箭头dolz
右侧的->
,然后运行->
后面的代码。请注意,这意味着 dolz
匹配任何值。
这就是为什么编译器警告你第二种情况
| _ -> aux dolz maks ((Random.int maks) :: acc)
从未使用过。
对于你的第二个问题,代码不会崩溃,因为你的代码类型不正确,因此无法编译。
Random.self_init
初始化PRNG的种子。您应该在程序中调用它一次,而不是每次调用 randlist
时都调用它。
您想要完成的事情可以实现,而无需计算累积列表的长度。您只需在每次迭代时将长度参数减一,并在小于或等于
acc
时返回 0
。
let randlist count max =
let rec aux c m acc =
if c <= 0 then acc
else aux (c-1) m (Random.init max :: acc)
in
aux count max []
当然,这一切只是一种复杂的写法:
let randlist count max =
List.init count (fun _ -> Random.int max)
这里
List.init
函数为我们处理迭代。实现一个等效的函数可能会揭示它的工作原理。
let list_init n f =
let rec list_init' n f acc =
if n <= 0 then acc
else list_init' (n-1) f (f (n-1) :: acc)
in
list_init' n f []
tail_mod_cons
来避免使用具有显式累加器的辅助函数:
let[@tail_mod_cons] list_init n f =
if n <= 0 then []
else
let r = f n in
r :: list_init f (n - 1)
这与
List.init
实际上实现的方式非常相似。
let[@tail_mod_cons] rec init i last f = if i > last then [] else if i = last then [f i] else let r1 = f i in let r2 = f (i+1) in r1 :: r2 :: init (i+2) last f let init len f = if len < 0 then invalid_arg "List.init" else init 0 (len - 1) f