ocaml中的急切副作用(printf)

use*_*818 0 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
Run Code Online (Sandbox Code Playgroud)

did*_*erc 5

默认情况下,Ocaml 中的效果是急切的:据说该语言具有急切的评估1,与诸如Haskell这样的惰性语言相对。

您看到的结果是由于的输出原语完成了缓冲stdout。只需用Pervasives.flush stdout或冲洗缓冲区即可Pervasives.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
Run Code Online (Sandbox Code Playgroud)

(1)但是Ocaml还支持通过模块进行某种形式的延迟评估Lazy,但是评估必须在某些情况下明确触发。