ocaml 中的 Eager 副作用 (printf)

Eager side effect (printf) in ocaml

新手问题:

假设我有一个非常慢的函数 do_sth,它适用于范围 1 到 n。我想在循环时打印 do_sth i 的结果。这个怎么做?天真的尝试失败了,因为值只会在整个循环后打印:

let rec loop i =
  if i>1000 then 0
  else
    let fi = do_sth i in
    (
    Printf.printf "%d %d\n" i fi;
    fi + loop (i+1)
    )

let f_sum = loop 1

不如改为执行以下操作:

let fi = do_sth i in
let () = Printf.printf "%d %d\n" i fi in
fi + loop (i+1)

Ocaml 中的效果 默认是急切的:据说该语言具有急切的求值1,这与所谓的惰性语言相反像 Haskell.

您看到的结果是由于 stdout 的输出原语完成的缓冲。只需使用 Pervasives.flush stdoutPervasives.flush_all () 刷新缓冲区即可提供所需的行为。

另外,您可以通过尾递归来优化您的函数:不是在递归调用之后求和,而是将结果累加到函数参数中:

let loop i =
  let rec loop r i =
    if i>1000 then r
    else
      let fi = do_sth i in (
        Printf.printf "%d %d\n" i fi;
        flush stdout;
        loop (r+fi) (i+1)
      )
  in loop 0 i

(1) 然而,Ocaml 也通过模块 Lazy 支持某种惰性求值,但在某些情况下必须显式触发求值。