将函数注入计算表达式

时间:2015-04-14 18:41:47

标签: dependency-injection functional-programming f#

以下代码示例来自Scott Wlaschin的网站F# for fun and profit.

type LoggingBuilder() =
    let log p = printfn "expression is %A" p

    member this.Bind(x, f) = 
        log x
        f x

    member this.Return(x) = 
        x

let logger = new LoggingBuilder()

let loggedWorkflow = 
    logger
        {
        let! x = 42
        let! y = 43
        let! z = x + y
        return z
        }

有没有办法将函数而不是printfn注入LoggingBuilder()

2 个答案:

答案 0 :(得分:6)

您只需将参数添加到构建器类型:

type LoggingBuilder(lf: obj -> unit) =
    let log p = lf p

    member this.Bind(x, f) = 
        log x
        f x

    member this.Return(x) = 
        x

let logger = new LoggingBuilder(printfn "expression is %A")

如果要使输入类型比obj更具体,可以使构建器通用。例如

type LoggingBuilder<'a>(lf: 'a -> unit) =
    ...

let logger = new LoggingBuilder<int>(printfn "Got %i")

答案 1 :(得分:0)

如果您打算将printfn替换为NLog等记录器,则可以使用Printf.ksprintf

open NLog
open NLog.Config
open NLog.Targets

let private logger =
    let config = new LoggingConfiguration()
    let consoleTarget = new ColoredConsoleTarget()
    config.AddTarget("console", consoleTarget)
    consoleTarget.Layout <- Layouts.SimpleLayout.FromString
        @"${longdate}|${level:uppercase=true}|${logger}|${message}"

    let rule = new LoggingRule("*", LogLevel.Debug, consoleTarget)
    config.LoggingRules.Add rule

    LogManager.Configuration <- config
    LogManager.GetLogger "MyLogger"

type LoggingBuilder(lf: string -> unit) =
    let log format =
        let doAfter (s: string) = lf s
        Printf.ksprintf doAfter format

    member this.Bind(x, f) = 
        log "%A" x
        f x

    member this.Return(x) = 
        x

let logger = new LoggingBuilder(logger.Info)