是否可以创建一个记录类型,其字段是一个采用泛型参数的函数,而不是在创建记录时指定类型?

时间:2015-10-23 22:19:27

标签: f#

我想定义以下记录类型:

type LogFuncs = {
    LogWithLabel : string -> 'a -> unit
    LogWithLabelAndReturn : string -> 'a -> 'a }

目的是我可以定义string -> unit的一个函数,然后使用它来派生几个便利函数,如下所示:

let makeLogFuncs outputFunc =
    let logWithLabelFunc label value = sprintf "%s: %A" label value |> outputFunc
    let logWithLabelAndReturnFunc label value = logWithLabelFunc label value; value
    {   LogWithLabel = logWithLabelFunc
        LogWithLabelAndReturn = logWithLabelAndReturnFunc  }

但是,如果没有在创建LogFuncs类型的实例时指定<'a>,编译器将不允许我这样做,这不是我想要做的 - 我希望能够调用此函数任何 'a。 (我还想提供相关的功能,因此使用记录类型。)

是否可以使用包含类型参数的字段定义记录类型,该字段不是记录类型本身的类型参数?

2 个答案:

答案 0 :(得分:3)

我认为记录类型不可能。但我可以定义一个,它提供了我想要的机制:

type Logger (outputFunc: string->unit) =
    member __.LogWithLabel label value = sprintf "%s: %A" label value |> outputFunc
    member x.LogWithLabelAndReturn label value = x.LogWithLabel label value; value

然后我可以做:

let log = new Loggery (printfn "%s")

let ``result should equal 5`` = 5 |> log.LogWithLabelAndReturn "Beans"

...并正确打印"Beans: 5"并返回5

答案 1 :(得分:0)

您可以将记录本身设为通用:

type LogFuncs<'a> = {
    LogWithLabel : string -> 'a -> unit
    LogWithLabelAndReturn : string -> 'a -> 'a }

这也使makeLogFuncs成为通用的。它仍然可以使用,但可能不是你想要的方式:

(makeLogFuncs (printfn "%s")).LogWithLabel "Number" 42
(makeLogFuncs (printfn "%s")).LogWithLabelAndReturn "Number" 42
(makeLogFuncs (printfn "%s")).LogWithLabel "Text" "Foo"
(makeLogFuncs (printfn "%s")).LogWithLabelAndReturn "Text" "Foo"

正如 Overlord Zurg 提供的答案所暗示的那样,OP方法非常面向对象,因此如果您想以这种方式设计系统,请使用对象。