OCaml简介

5

我现在正在尝试学习OCaml,想从一个小程序开始,生成所有的位组合:

["0","0","0"]
["0","0","1"]
["0","1","0"]

我的想法是以下代码:

let rec bitstr length list =
  if length = 0 then
    list
  else begin
    bitstr (length-1)("0"::list);
    bitstr (length-1)("1"::list);
  end;;

但是我遇到了以下错误:
Warning S: this expression should have type unit.
val bitstr : int -> string list -> string list = <fun>
# bitstr 3 [];;
- : string list = ["1"; "1"; "1"]

我不明白需要改变什么,你可以帮助我吗?

最好的祝福 Philipp

3个回答

14

begin foo; bar end 执行 foo 并且忽略其结果, 然后执行bar。因为只有当 foo 有副作用而没有有意义的返回值时才会有意义,否则会导致程序员错误(即程序员实际上不想丢弃结果)- 正如此处情况一样,所以 ocaml 会发出警告,如果foo具有除了unit之外的返回值,则每个其他返回值都可能是程序员的错误。

在这种情况下,使用 "0" 计算列表然后将其丢弃确实没有意义。您可能想要连接两个列表。您可以使用 @ 运算符来完成此操作:

let rec bitstr length list =
  if length = 0 then
    [list]
  else
    bitstr (length-1)("0"::list) @ bitstr (length-1)("1"::list);;

需要注意的是,我还使得当length = 0时返回的结果为[list]而不仅仅是list,因此结果是一个列表套列表,而不是一个平坦的列表。


5
虽然sepp2k的答案很准确,但我想添加以下替代方案(它与您提出的签名不匹配,但实际上可以实现您想要的功能):
let rec bitstr = function
   0 -> [[]]
 | n -> let f e = List.map (fun x -> e :: x) and l = bitstr (n-1) in 
        (f "0" l)@(f "1" l);;

第一个区别是在调用函数时不需要传递空列表,调用函数bitsr 2返回[["0"; "0"]; ["0"; "1"]; ["1"; "0"]; ["1"; "1"]]。其次,它返回有序二进制值的列表。但更重要的是,在我看来,它更接近ocaml精神。


谢谢您的回复。我喜欢听取其他想法!由于我不熟悉Ocaml,这个解决方案更加复杂难懂。我会在几天后尝试一下 ;) - Philipp Andre

0
我喜欢获取其他想法!
let rec gen_x acc e1 e2 n = match n with
| 0 -> acc
| n -> (
  let l = List.map (fun x -> e1 :: x) acc in
  let r = List.map (fun x -> e2 :: x) acc in
  gen_x (l @ r) e1 e2 (n - 1)
);;

let rec gen_string = gen_x [[]] "0" "1"
let rec gen_int    = gen_x [[]]  0   1

gen_string 2
gen_int    2

结果:

[["0"; "0"]; ["0"; "1"]; ["1"; "0"]; ["1"; "1"]]

[[0; 0]; [0; 1]; [1; 0]; [1; 1]]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接