如何在F#中制作可变的泛型函数

时间:2018-08-04 18:06:31

标签: f#

在FSI中,我想“轻松地”替换/模拟一个功能。这对于快速迭代非常有用,除非该函数是通用函数,否则效果很好。例如:

// ... deep in some DLL
let int_op (x:int) = "hello "+(x.ToString())
let mutable realInt_op = int_op   // OK!

let generic_op (x:'a) = "hello "+(x.ToString())
let mutable real_op = generic_op   // Err: Value restriction!

// ... later in FSI
let mock_op x = "Waaaaasup "+(x.ToString())
do 
    real_op <- mock_op

那么,有没有一种很好的方法来“快速”模拟通用函数?

1 个答案:

答案 0 :(得分:1)

我可以看到3种可能性。 正如Jwotsy所提到的,如果您想这样做,可以将其遮盖。

let intop (x:int) = "hello "+(x.ToString())
let mutable realIntop = intop

let inline genericop (x:'a) = "hello "+(x.ToString())
let realop = genericop 

let mockop x = "Waaaaasup "+(x.ToString())
do 
    let realop = mockop
    realop "" |> ignore //to make compile with partial example

这必须在表达式内,否则将不起作用:

let mockop x = "Waaaaasup "+(x.ToString())
let realop = mockop // Duplicate definition of value 'realop'
do ...

或者,由于您在这里与不变性作斗争,因此可以转换为F#的OO功能:

let genericOp (x:'a) = sprintf "hello %A" x
type Container () = 
    member this.GenericOp<'a>(x:'a) = "hello generic " + (x.ToString())
    member val intOp = genericOp with get,set
    member val stringOp = genericOp with get,set

let c = new Container()

printfn "%s" (c.GenericOp "Test")
printfn "%s" (c.GenericOp 1)

printfn "%s" (c.stringOp "Test")
printfn "%s" (c.intOp 1)

let mockOp (x:'a) = sprintf "Mocked %A" x
do c.stringOp <- mockOp
do c.intOp <- mockOp

printfn "%s" (c.stringOp "Test")
printfn "%s" (c.intOp 1)

结果是:

hello generic Test
hello generic 1
hello "Test"
hello 1
Mocked "Test"
Mocked 1

最后,您可以更改方法并使用组成,以便感染要模拟的功能,然后在注入的内容之间进行切换。像这样:

let generic_op (x:'a) = "hello "+(x.ToString())
let int_op (x:int) = "hello "+(x.ToString())
let realInt_op = int_op
let real_op = generic_op
let mock_op x = "Waaaaasup "+(x.ToString())

let doSomething f x =
    do printfn "%s" (f x)

do doSomething realInt_op 1
do doSomething real_op "Real"
do doSomething mock_op "Mock"