F# 部分应用程序函数包装器不保留 return 参数函数的通用类型
F# partial application function wrapper does not keep return type generic for parameter function
TL DR:我正在尝试创建一个函数包装器。包装函数不带参数,但 returns 一个值。
我想这样做的原因是创建一个类似于“锁”的函数,但用于信号量。
在这里
let functionWrapper (param1) (f:(unit -> 'a)) =
printfn "Calling function %s" param1
f()
签名:(string -> (unit -> 'a) -> 'a)
到目前为止,一切都很好
现在让我们用一个参数来丰富 functionWrapper
let functionWrapperFoo = functionWrapper "Foo"
签名:((unit -> obj) -> obj)
由于某种原因,'a 在这里变为 obj..
现在终于想用这个功能再包裹一个
但是类型推断会将 functionWrapperFoo
的签名更改为 ((unit -> int) -> int)
,这会阻止之后将函数与其他类型一起使用。
let resultFooInt =
functionWrapperFoo (
fun _ ->
(42)
)
// Because I am using a string as a return type now, this one bellow won't compile
let resultFooString =
functionWrapperFoo (
fun _ ->
"42"
)
为什么我不能在第一次部分应用后保持此函数通用?
我确实找到了解决方法,但是我真的不明白这样做的原因。
我看到一些人 post 提到了关于部分应用的类似内容,但在我的例子中,我的包装函数没有参数
Keeping partially applied function generic
完整原码
let functionWrapper (param1) (f:(unit -> 'a)) =
printfn "Calling function %s" param1
f()
let functionWrapperFoo = functionWrapper "Foo"
let resultFooInt =
functionWrapperFoo (
fun _ ->
(42)
)
let resultFooString =
functionWrapperFoo (
fun _ ->
"42"
)
解决方法
let functionWrapper (param1) (f:(unit -> 'a)) =
printfn "Calling function %s" param1
f()
let functionWrapperFoo() = functionWrapper "Foo"
let resultFooInt =
functionWrapperFoo() (
fun _ ->
(42)
)
let resultFooString =
functionWrapperFoo() (
fun _ ->
"42"
)
如果您在第一个 full code
部分中将 f 定义为一个值,则 f 将成为完全类型化的,因此不再是通用的。编译器需要推断某种类型。
如果您使它保持 workaround
部分中的功能。它仍然是一个(通用)函数,这就是它起作用的原因。
你也可以再次指定函数参数,这样调用函数就没那么丑了:
let inline functionWrapper (param1) (f:(unit -> 'a)) =
printfn "Calling function %s" param1
f()
let functionWrapperFoo f = functionWrapper "Foo" f
let resultFooInt =
functionWrapperFoo (
fun _ ->
(42)
)
let resultFooString =
functionWrapperFoo (
fun _ ->
"42"
)
这是一个称为值限制的问题。在 this article on automatic generalization in F# and there are also good existing answers on SO.
中对此有相当详细的解释
基本问题是 F# 不允许您定义通用语法值。您的 functionWrapperFoo
被定义为一个值,即使用 let value = <expr>
。在这种情况下,该值不能是通用的,即使表达式 <expr>
实际上计算为一个函数。
您的解决方法有效,因为它使用 let func arg = <expr>
将句法声明转换为函数声明。在这里,编译器肯定知道它将成为一个函数。
正如 Tom 所提到的,更好的解决方法是在 functionWrapperFoo
定义中添加一个参数并将其传递给 functionWrapper
- 这样,它将在语法上被定义为一个函数并自动泛化将使它通用。
TL DR:我正在尝试创建一个函数包装器。包装函数不带参数,但 returns 一个值。
我想这样做的原因是创建一个类似于“锁”的函数,但用于信号量。
在这里
let functionWrapper (param1) (f:(unit -> 'a)) =
printfn "Calling function %s" param1
f()
签名:(string -> (unit -> 'a) -> 'a)
到目前为止,一切都很好
现在让我们用一个参数来丰富 functionWrapper
let functionWrapperFoo = functionWrapper "Foo"
签名:((unit -> obj) -> obj)
由于某种原因,'a 在这里变为 obj..
现在终于想用这个功能再包裹一个
但是类型推断会将 functionWrapperFoo
的签名更改为 ((unit -> int) -> int)
,这会阻止之后将函数与其他类型一起使用。
let resultFooInt =
functionWrapperFoo (
fun _ ->
(42)
)
// Because I am using a string as a return type now, this one bellow won't compile
let resultFooString =
functionWrapperFoo (
fun _ ->
"42"
)
为什么我不能在第一次部分应用后保持此函数通用?
我确实找到了解决方法,但是我真的不明白这样做的原因。
我看到一些人 post 提到了关于部分应用的类似内容,但在我的例子中,我的包装函数没有参数
Keeping partially applied function generic
完整原码
let functionWrapper (param1) (f:(unit -> 'a)) =
printfn "Calling function %s" param1
f()
let functionWrapperFoo = functionWrapper "Foo"
let resultFooInt =
functionWrapperFoo (
fun _ ->
(42)
)
let resultFooString =
functionWrapperFoo (
fun _ ->
"42"
)
解决方法
let functionWrapper (param1) (f:(unit -> 'a)) =
printfn "Calling function %s" param1
f()
let functionWrapperFoo() = functionWrapper "Foo"
let resultFooInt =
functionWrapperFoo() (
fun _ ->
(42)
)
let resultFooString =
functionWrapperFoo() (
fun _ ->
"42"
)
如果您在第一个 full code
部分中将 f 定义为一个值,则 f 将成为完全类型化的,因此不再是通用的。编译器需要推断某种类型。
如果您使它保持 workaround
部分中的功能。它仍然是一个(通用)函数,这就是它起作用的原因。
你也可以再次指定函数参数,这样调用函数就没那么丑了:
let inline functionWrapper (param1) (f:(unit -> 'a)) =
printfn "Calling function %s" param1
f()
let functionWrapperFoo f = functionWrapper "Foo" f
let resultFooInt =
functionWrapperFoo (
fun _ ->
(42)
)
let resultFooString =
functionWrapperFoo (
fun _ ->
"42"
)
这是一个称为值限制的问题。在 this article on automatic generalization in F# and there are also good existing answers on SO.
中对此有相当详细的解释基本问题是 F# 不允许您定义通用语法值。您的 functionWrapperFoo
被定义为一个值,即使用 let value = <expr>
。在这种情况下,该值不能是通用的,即使表达式 <expr>
实际上计算为一个函数。
您的解决方法有效,因为它使用 let func arg = <expr>
将句法声明转换为函数声明。在这里,编译器肯定知道它将成为一个函数。
正如 Tom 所提到的,更好的解决方法是在 functionWrapperFoo
定义中添加一个参数并将其传递给 functionWrapper
- 这样,它将在语法上被定义为一个函数并自动泛化将使它通用。