F# Can';t在F中创建函数的通用部分应用程序#
我正在寻找一种方法来解决这种非常确定的情况:我有一个函数工厂F# Can';t在F中创建函数的通用部分应用程序#,f#,F#,我正在寻找一种方法来解决这种非常确定的情况:我有一个函数工厂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 mak
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
在语法上不是一个函数(获取参数)而是一个值时,您会遇到“值限制”错误。我不打算在这里解释,因为在以前的帖子中已经有很多信息,比如:
编辑-如果要确保只调用一次g
(但仍希望代码是通用的),最简单的方法是添加未使用的unit
参数(使其成为函数),然后调用一次(确定通用参数)并多次使用结果:
let toF g =
let f x = g x
f
let f () = toF id
let fg = f ()
fg 1
fg 2
这是非常必要的,因为拥有一个泛型函数,但通过某些计算返回,实际上会在类型系统中创建一个微妙的漏洞——这就是“值限制”的原因。最简单的解决方案就是只添加一个类型注释。假设您只关心一种真正的类型,这是非常简单的:
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
类型FI不知道它是如何工作的:让f x=toF id x
不应该工作,因为toF id x
中有两个参数,而声明的toF
只获取一个参数g
。我的意思是x只是被忽略了还是什么?let f x=
定义了一个函数(恰好返回了带另一个参数的函数),而let f=
定义了一个值(实际上是一个带两个参数的函数),这实际上只是一个简单的语法条件-它必须是一个函数(至少带一些参数)Tomas,您建议的方法也不起作用(只要我们希望fg
是通用的),您的示例只起作用,因为您在使用数字定义后立即调用fg
,因此F#推断fg
对数字进行操作,如果您删除fg 1
和fg 2
,您将得到相同的错误。。。函数似乎不是F#中的一等公民,因为它不能被返回并赋值。@AlekseyBykov你从哪里得到这个想法的?当然,你可以给一个值赋值,这就是你一直在做的事情,这就是F#的全部本质。