2013-10-24 16 views
2

我正在寻找一种方法来解决这种非常特定的情况:我有一个函数工厂toF,它采用函数参数g并基于它创建一个结果函数f无法在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得到一个由函数,然后才调用由上x功能。

Creating f using g 
x: 1 
Creating f using g 
x: 1 

所以基本上的组成是在通过后续调用每次调用ftoF创建。但这正是我想要避免的。通过定义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() 

回答

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 

这是可悲的需要,因为有一个功能是通用的,而是由一些计算返回实际上创造了一个微妙的孔类型系统 - 这就是“价值限制”的原因。

+0

let toF g = let f x = g x f let f : _ -> int = toF id 

如果你真的需要在不同类型的呼叫f,那么您可以在一个通用型包装它我不明白它是如何工作的:'让FX =因为有2个参数的'TOF ID x' TOF ID x'不应该工作而作为申报'toF'仅得到一个参数'g'。我的意思是x只是被忽略或者是什么? –

+0

'让FX ='定义一个函数(恰好返回功能服用另一种说法),而'令f ='定义的值(这实际上是两个参数的函数) –

+0

这仅仅是一个简单的语法条件 - 它作为一个函数(至少有一些参数) –

1

最简单的解决方法就是增加一个类型注释。假设只有一个你关心真正的类型,这完全是直截了当:

type F<'t>() = 
    static member val f : _ -> 't = toF id 

let blah = F.f "blah" 
let one = F.f 1 
+0

尼斯...这似乎是一个功能在F#一流的公民,因为它不能返回,分配给一个值。 –

+0

@AlekseyBykov你在哪里得到这个想法?当然,你可以为一个值赋一个函数,这就是你一直在做的事,这就是F#的全部本质。 – Abel

相关问题