Generics 将curried kprintf作为函数参数传递

Generics 将curried kprintf作为函数参数传递,generics,f#,functional-programming,printf,Generics,F#,Functional Programming,Printf,我在将Printf类函数作为参数传递时遇到了一个问题。 最终目标是创建一个定制的日志函数,该函数可以被注入到其他假定日志的方法中。所以,我学会了如何使用kprintf。但是如何将其结果向上传递到调用堆栈。 谁能帮我使下面的代码正常工作 open System type logging () = let logWarning = let logToConsole msg = Console.WriteLine("WARN: {0} {1}", DateTime.Now,

我在将Printf类函数作为参数传递时遇到了一个问题。 最终目标是创建一个定制的日志函数,该函数可以被注入到其他假定日志的方法中。所以,我学会了如何使用kprintf。但是如何将其结果向上传递到调用堆栈。 谁能帮我使下面的代码正常工作

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参数上的-type推断不允许编译对此函数的第二次调用。 我如何才能使它工作,使我可以使用warningLogger,作为正常的printf类型的函数? 非常感谢您。

一般来说,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())