在f#中捕获print语句

时间:2017-03-15 22:53:06

标签: f#

我想知道是否有一种很好的方法来定义一个函数xoco70/kendo-tournaments,它接受​​一个函数captureOutput,该函数可能包含print语句并返回f打印的任何内容。如,

f

我在想,也许有一种很好的方法可以与let f x = print "%s" x let op = captureOutput (f "Hello World") val op : string = "Hello World" 异步地进行此操作,但我无法解决任何问题。

干杯

编辑:

根据Fyodor Soikin的评论,以下代码可以满足我的需求:

Console.ReadLine()

2 个答案:

答案 0 :(得分:5)

您可以通过Console.SetOut临时替换标准输出编写器。

但要注意:此替换也会影响在其他线程上执行的代码并捕获其输出,并与函数的输出混合。这基本上就是所谓的“黑客”。

如果这只是一个非常小的实用工具,永远不会变得更复杂,那么这很好。但这永远不应成为生产系统的一部分。如果你正在开发复杂的东西的一部分,我建议改变函数本身,通过打印功能对其进行参数化:

type Printer = abstract member print (fmt: StringFormat<'T, unit>) : 'T

let captureOutput f =
   let mutable output = ""
   let print s = output <- output + s
   f { new Printer with member _.print fmt = kprintf print fmt }
   output

let f x (p: Printer) = p.print "%s" x 
let op = captureOutput (f "Hello World") 

(这个例子必须使用一个接口,因为没有它,print函数会失去通用性)

答案 1 :(得分:3)

实施@FyodorSoikin的建议(我只是在之后看到我写了这个):

let captureOutput f =
    use writer = new StringWriter()
    use restoreOut =
        let origOut = Console.Out
        { new IDisposable with member __.Dispose() = Console.SetOut origOut }
    Console.SetOut writer
    f ()
    writer.ToString ()

let f x () = printf "%s" x
let op = captureOutput (f "Hello World")

(Nb必须将额外的参数添加到f以便可以部分应用 - captureOutput必须采用函数,而不是值。)

IDisposable的对象表达式用于包装清理,以便对f的调用是异常安全的。