使包装的 F# SRTP 函数通用
Make wrapped F# SRTP function generic
我有一个使用静态解析类型参数的通用函数
let inline divide a b = a / b
签名^a -> ^a -> ^a
我可以创建一个包装函数
let log f =
let result = f()
printfn "Result: %A" result
result
如果我再创建一个像
这样的函数
let loggedDivide a b = log (fun () -> divide a b)
它的签名是float -> float -> float
而不是^a -> ^a -> ^a
,意思是
loggedDivide 2.0 5.0
loggedDivide 2 5 //error
如何做到这一点?
注意,这样的事情忽略了尝试重用函数的要点
let logValue a = printfn "Result: %A" a
divide 2.0 5.0 |> logValue
divide 2 5 |> logValue
事情不会以这种方式保持通用
let logValueAndReturn a =
printfn "Result: %A" a
a
let divideAndLog a b = divide a b |> logValue
divideAndLog 2.0 5.0
divideAndLog 2 5 //error
您还必须使派生函数内联:
let inline loggedDivide a b = log (fun () -> divide a b)
这将允许传播约束:
val inline loggedDivide :
a: ^a -> b: ^b -> ^c
when ( ^a or ^b) : (static member ( / ) : ^a * ^b -> ^c)
原因是 SRTP 是一个 F# 编译器功能,它在编译时解析,因此函数通过在调用站点内联得到专门化。
如果你想让你的函数保持通用,它必须是内联的。
请注意,您将函数推断为使用 int
运算的原因是因为这是 \
和其他数学运算符的默认值。否则你会得到一个错误指示歧义。
我有一个使用静态解析类型参数的通用函数
let inline divide a b = a / b
签名^a -> ^a -> ^a
我可以创建一个包装函数
let log f =
let result = f()
printfn "Result: %A" result
result
如果我再创建一个像
这样的函数let loggedDivide a b = log (fun () -> divide a b)
它的签名是float -> float -> float
而不是^a -> ^a -> ^a
,意思是
loggedDivide 2.0 5.0
loggedDivide 2 5 //error
如何做到这一点?
注意,这样的事情忽略了尝试重用函数的要点
let logValue a = printfn "Result: %A" a
divide 2.0 5.0 |> logValue
divide 2 5 |> logValue
事情不会以这种方式保持通用
let logValueAndReturn a =
printfn "Result: %A" a
a
let divideAndLog a b = divide a b |> logValue
divideAndLog 2.0 5.0
divideAndLog 2 5 //error
您还必须使派生函数内联:
let inline loggedDivide a b = log (fun () -> divide a b)
这将允许传播约束:
val inline loggedDivide :
a: ^a -> b: ^b -> ^c
when ( ^a or ^b) : (static member ( / ) : ^a * ^b -> ^c)
原因是 SRTP 是一个 F# 编译器功能,它在编译时解析,因此函数通过在调用站点内联得到专门化。
如果你想让你的函数保持通用,它必须是内联的。
请注意,您将函数推断为使用 int
运算的原因是因为这是 \
和其他数学运算符的默认值。否则你会得到一个错误指示歧义。