我正在寻找一种方法来解决这种非常特殊的情况:我有一个函数工厂toF
,它接受一个函数参数g
并基于它创建一个结果函数{{1} }
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
基本上发生的是每次我调用函数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
上的组合函数。 / p>
x
因此,通过后续调用Creating f using g
x: 1
Creating f using g
x: 1
,每次调用f
时都会创建合成。但这正是我试图避免的。通过定义toF
我希望关闭一个单一的时间然后能够立即调用它。所以我期待的输出是:
let f = toF id
更新2
由于同样的原因,以下内容无效:
Creating f using g
x: 1
x: 1
答案 0 :(得分:6)
你只需要使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
这是非常需要的,因为拥有一个通用的函数但是通过某种计算返回的函数实际上会在类型系统中创建一个微妙的漏洞 - 这就是“价值限制”的原因。
答案 1 :(得分:1)
最简单的解决方案是添加类型注释。假设你只关心一种真实的类型,这很简单:
let toF g =
let f x = g x
f
let f : _ -> int = toF id
如果您确实需要以不同类型调用f
,那么您可以将其包装为通用类型:
type F<'t>() =
static member val f : _ -> 't = toF id
let blah = F.f "blah"
let one = F.f 1