OCaml:Stream.peek没有消耗线?

pri*_*hey 3 ocaml stream

我正在研究一个迭代输入文件的程序,其中包含可变数量的"程序",结尾为"0".如果我从文件的顶部开始,我的函数运行正常,但由于某种原因,通过查看下一个字符是'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;;
Run Code Online (Sandbox Code Playgroud)

根据我的阅读,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;;
Run Code Online (Sandbox Code Playgroud)

这是一个示例输入:

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
Run Code Online (Sandbox Code Playgroud)

cam*_*ter 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 Code Online (Sandbox Code Playgroud)

(<>)在这里使用结构不平等.除了它和省略的run_in_channel部分,代码对我来说很好.

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

- 编辑 -

代码中还有另一个问题,最初没有透露.

从中创建流后in_channel.不要自己触摸,直到你要关闭它close_in!让流是唯一的读者.

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