我正在寻找一种方法来解决这种非常特定的情况:我有一个函数工厂toF
,它接受一个函数参数g
,并基于它创建一个结果函数 f
let toF g =
let f x = g x
f
let f = toF id
问题是我得到了一个
error FS0030: Value restriction. The value 'f' has been inferred to have generic type val f : ('_a -> '_a) Either make the arguments to 'f' explicit or, if you do not intend for it to be generic, add a type annotation.
我可以添加类型注释(我并不急于这样做)或者我可以像这样重写它:
let f' g x = g x
let f x = f' id x
我不喜欢这样做,因为如果我这样做,那么每次调用 f
时,我都会再次调用 f'
并指定 g
一路走来。虽然第一个示例将 g
保留在闭包中并且只需要一次调用。
更新(对于 Tomas)
我已经尝试了你的建议。
let toF g =
printfn "Creating f using g"
let f x =
printfn "x: %A" x
g x
f
let f x = toF id x
let ``test``() =
1 |> f |> f |> ignore
基本上发生的事情是,每次我调用函数 f
时,它首先调用 toF id
获取一个组合函数,然后才调用该组合函数x
。
Creating f using g
x: 1
Creating f using g
x: 1
所以本质上,组合是在每次调用 f
时通过随后调用 toF
创建的。但这正是我试图避免的。通过定义 let f = toF id
我希望一次性获得一个闭包然后能够立即调用它。所以我期望的输出是:
Creating f using g
x: 1
x: 1
更新 2
出于同样的原因,以下内容也不起作用:
let toF g =
printfn "Creating f using g"
let f x =
printfn "x: %A" x
g x
f
let f() = toF id
let fg = f()
最佳答案
你只需要让f
成为一个句法函数:
let toF g =
let f x = g x
f
let f x = toF id x
当 f
在语法上不是一个函数(带参数)而是一个值时,您会遇到“值限制”错误。我不打算在这里解释它,因为在以前的帖子中已经有很好的信息,例如:Understanding F# Value Restriction Errors。
编辑 - 如果你想确保 g
只被调用一次(但仍然希望代码是通用的)那么最简单的方法是添加未使用的 unit
参数(使其成为一个函数),然后调用它一次(确定通用参数)并多次使用结果:
let toF g =
let f x = g x
f
let f () = toF id
let fg = f ()
fg 1
fg 2
遗憾的是,这是必需的,因为拥有一个通用的函数,但由某些计算返回实际上会在类型系统中创建一个微妙的漏洞 - 这就是“值限制”的原因。
关于f# - 无法在 F# 中创建函数的通用部分应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19572242/