有没有办法使用printf在F#interactive中更新同一行?

时间:2017-12-06 13:11:10

标签: f# read-eval-print-loop f#-interactive

大家好!

我在Visual Studio Community 2017中使用F#进行脚本编写。我处理大型数据集,我经常使用recursvive函数循环。为了大致了解这需要多长时间,我目前正在使用printfn来打印当前的迭代索引。虽然我猜这听起来很简单,但这是一个例子:

let foo f bar maxIter =
    let rec loop currentIter resultList=
        if currentIter<maxIter then
            printfn "current Iteration: %i" currentIter
            loop (currentIter+1) ((f bar)::resultList)
        else
            List.rev resultList
    loop 0 []

enter image description here

这实际上是fsi窗口的混乱,如果我在更大的功能中在不同的步骤上另外打印其他字符串,则无法遵循。

我的问题如下:我能以某种方式用fsi更新当前迭代次数中的一行吗?我尝试过使用printf和回车:

printf "%i\r"

但这与使用printfn的结果相同。

提前感谢您的帮助!

编辑:正如此线程上的评论者指出的那样,目前似乎无法在VS FSI中执行此操作。

1 个答案:

答案 0 :(得分:2)

可以通过设置光标位置来实现(自包含)迭代计数器:

let rec progress i : unit =
    printf "%i" i
    System.Threading.Thread.Sleep 1000
    System.Console.SetCursorPosition(0, System.Console.CursorTop)
    progress (i+1)

progress 0

注1:这将覆盖当前行上的任何内容,即除非您实现某些同步方法或除了进度之外始终使用printfn,否则将覆盖其他日志输出。可以通过以下方式观察到此行为:

open System
open System.Threading

let rec progress i p : unit =
    printf "%s %i" p i
    Thread.Sleep 1000
    Console.SetCursorPosition(0, Console.CursorTop)
    progress (i+1) p

Tasks.Task.Run(fun () -> progress 0 "t1")
Thread.Sleep 500
Tasks.Task.Run(fun () -> progress 0 "t2")

注意2:由于VS的限制,这在VisualStudio FSI中不起作用。它可以在VS Code,控制台(编译为EXE,运行CMD或PowerShell)或使用非VS FSI(在Windows 10,VS 15.5.1上测试)中工作。