OCaml:Stream.peek没有消耗线?

时间:2014-03-04 04:08:47

标签: stream ocaml

我正在研究一个迭代输入文件的程序,其中包含可变数量的“程序”,并以“0”结尾。如果我从文件的顶部开始,我的函数运行正常,但由于某种原因,通过查看下一个char为'0'(表示文件的结尾)来消耗一行。

这是我的代码:

let line_stream_of_channel channel =
    Stream.from
      (fun _ ->
         try Some (input_line channel) with End_of_file -> None);;

let in_channel = open_in "dull.in" in
let line_stream = line_stream_of_channel in_channel in
while Stream.peek line_stream != Some "0" do
    run in_channel;
    print_string "...\n";
done;;

从我读过的内容来看,Stream.peek不应该消耗一条线,所以也许问题不是来自那个,但如果没有,我无法弄清楚它在做什么。有什么想法吗?

修改以下是我的整个程序:

let hello c = 
    print_char c;;

let hello_int c =
    print_int c;
    print_char '\n';;

let ios = int_of_string;;

let rec print_string_list = function 
    [] -> print_string "\n"
    | h::t -> print_string h ; print_string " " ; print_string_list t;;

let rec print_int_list = function 
    [] -> print_string "\n"
    | h::t -> print_int h ; print_string " " ; print_int_list t;;

let rec append l i =
    match l with
    [] -> [i]
    | h :: t -> h :: (append t i);;

let line_stream_of_channel channel =
    Stream.from
    (fun _ ->
        try Some (input_line channel) with End_of_file -> None);;

let string_to_int_list str_list int_list=
    let len = List.length str_list in
    for i = 0 to len - 1 do
        int_list := append !int_list (ios (List.nth str_list i));
    done;;

let get_option = function
  | Some x -> x
  | None   -> raise (Invalid_argument "Option.get");;

let chomp_line ns in_channel = 
    let s = input_line in_channel in
    let len = String.length s in
    let start_pos = ref 0 in
    for i = 0 to len do
        if i == len then
            let word = String.sub s !start_pos (i - !start_pos) in
            ns := append !ns word;
        else if s.[i] == ' ' then
            let word = String.sub s !start_pos (i - !start_pos) in
            ns := append !ns word;
            start_pos := i + 1;
    done;;

let run in_channel = 

    let ns = ref [] in
    chomp_line ns in_channel;
    let n = ios (List.nth !ns 0) in
    let p = ios (List.nth !ns 1) in
    let s = ios (List.nth !ns 2) in
    print_string "num dulls: "; hello_int n;
    print_string "num programs: "; hello_int p;
    print_string "num state transitions: "; hello_int s;

    let dull_sizes = ref [] in
    chomp_line dull_sizes in_channel;
    let int_dull_sizes = ref [] in
    string_to_int_list !dull_sizes int_dull_sizes;
    print_string "size of dulls: "; print_int_list !int_dull_sizes;

    let program_sizes = ref [] in
    let program_dulls = ref [] in
    for i = 0 to p - 1 do
        let program = ref [] in
        chomp_line program in_channel;
        program_sizes := append !program_sizes (List.nth !program 0);
        program_dulls := append !program_dulls (List.nth !program 1);
    done;
    let int_program_sizes = ref [] in
    string_to_int_list !program_sizes int_program_sizes;
    print_string "program sizes: "; print_int_list !int_program_sizes;
    print_string "program dulls: "; print_string_list !program_dulls;

    let transitions = ref [] in
    chomp_line transitions in_channel;
    let int_transitions = ref [] in
    string_to_int_list !transitions int_transitions;
    for i = 0 to s - 1 do
        hello_int (List.nth !int_transitions i)
    done
;;

let in_channel = open_in "dull.in" in
let line_stream = line_stream_of_channel in_channel in
while Stream.peek line_stream <> Some "0" do
    run in_channel;
done;;

这是一个示例输入:

2 2 3
500 600
100 A
200 B
2 1 2
5 4 8
100 400 200 500 300
250 AC
360 ACE
120 AB
40 DE
2 3 4 -3 1 2 -2 1
0

1 个答案:

答案 0 :(得分:6)

(!=)是物理(指针)不等式,测试无法检测到您的结束标记0。当0被窥视时,Stream.peek返回Some 0,但它与不等式检查右手的Some 0不同,因此循环永远不会终止,直到它崩溃为止EOF。

以下演示了正在发生的事情:

# Some 0 != Some 0;;
- : bool = true
# let x = Some 0 in x != x;;
- : bool = false

在此处使用(<>)结构不等式。除了它和省略的run_in_channel部分,代码对我来说很好。

黄金法则:除非你真的需要,否则不要使用物理平等(==)(!=)。通常,坚持结构平等(=)(<>)

- 编辑 -

代码中还有另一个问题,最初未透露。

in_channel创建流后。在close_in之前关闭它之前,请勿自行触摸!让流是唯一的读者。

流的好处是,一旦创建,您将无需在实际读数发生时进行处理。你仍然可以直接访问该频道,但它完全破坏了这个好处。只是不要这样做。在Stream.next中使用Stream.peekinput_line代替run