将curried kprintf作为函数参数传递

时间:2014-08-22 13:57:30

标签: generics f# functional-programming printf

我将 Printf 类函数作为参数传递出来了。 最终目标是创建一个自定义日志记录功能,可以注入其他假定日志记录的方法。所以,我学会了如何使用 kprintf 。但是如何将其结果传递给callstack。 有人可以帮我制作以下代码吗?

open System

type logging () =
    let logWarning =
        let logToConsole msg = Console.WriteLine("WARN: {0} {1}", DateTime.Now, msg)
        fun fmt -> Printf.kprintf logToConsole fmt

    let doThingsWithLogging warningLogger =
        warningLogger "%s %d %f" "DoThingsWithLogger" 3 3.29
        warningLogger "%d %A" 3 "DoThingsAgain"

    member __.RunTest() =
        logWarning "%s %d %f" "String, int, float" 12 38.8
        logWarning "%d %f %s" 83 128.9 "int, float, string"

        doThingsWithLogging logWarning

let test = logging()
test.RunTest ()

如果您尝试在FSI中运行它,您将立即看到问题出在哪里 - 在 warningLogger 参数上键入推断不允许编译对此函数的第二次调用。 我怎样才能使它工作,我可以使用 warningLogger 作为普通的 printf 类型的函数? 非常感谢你提前。

1 个答案:

答案 0 :(得分:3)

通常,F#不允许您将泛型函数作为参数传递。这在您的示例中并不容易看到(因为格式字符串更棘手),但您可以在以下更简单的情况下看到:

let foo f =  
  f 1
  f 1.0

没有办法告诉编译器参数f应该是泛型函数'a -> unit,所以这不会编译。

您示例中最简单的解决方案可能是定义一个具有通用LogWraning方法的类型,然后传递该类型的实例。像这样:

type Logger() =
  member x.LogWarning fmt =
    let logMessage msg = Console.WriteLine("WARN: {0} {1}", DateTime.Now, msg)
    Printf.kprintf logMessage fmt

let doThingsWithLogging (logger:Logger) =
    logger.LogWarning "%s %d %f" "DoThingsWithLogger" 3 3.29
    logger.LogWarning "%d %A" 3 "DoThingsAgain"

doThingsWithLogging (Logger())