【问题标题】:Pass curried kprintf as function argument [duplicate]将 curried kprintf 作为函数参数传递 [重复]
【发布时间】:2014-08-22 13:57:29
【问题描述】:

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

【问题讨论】:

    标签: generics f# functional-programming printf


    【解决方案1】:

    通常,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())
    

    【讨论】:

      猜你喜欢
      • 2013-08-13
      • 2019-07-23
      • 2011-04-07
      • 2013-03-16
      • 1970-01-01
      • 2020-08-03
      • 2018-08-30
      • 1970-01-01
      相关资源
      最近更新 更多