我想定义以下记录类型:
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
。 (我还想提供相关的功能,因此使用记录类型。)
是否可以使用包含类型参数的字段定义记录类型,该字段不是记录类型本身的类型参数?
答案 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方法非常面向对象,因此如果您想以这种方式设计系统,请使用对象。