你能解释为什么一个有效而另一个无效吗?
鉴于
//fu : unit -> unit
let fu() = ();;
此作品
//exec : (unit -> unit) -> int -> unit
let exec (f:(unit -> unit)) (data:int) = f();;
//this works, and p : int -> unit
let p = exec fu;;
它适用于其他类型的data
,例如string
,long
等。
这不起作用
//exec : (unit -> unit) -> obj -> unit
let exec (f:(unit -> unit)) (data:obj) = f();;
let p = exec fu;;
我收到以下错误:
错误FS0030:值限制。值'p'被推断为具有泛型类型 val p:('_ a - > unit)
要么将'p'的参数显式化,要么如果你不打算将它作为泛型,那么添加一个类型注释。
请注意,这些情况之间的唯一区别是data
参数的类型。
当它是obj
或System.Object
或'a
时 - 它不起作用。
另一件事是,如果data
的类型为obj
,则会发生以下情况:
//Data type is obj
let exec (f:(unit -> unit)) (data:obj) = f();;
//specifying parameters explicitly
let p x = exec fu x;;
现在p
的签名为'a -> unit
,而不是obj -> unit
。
所以问题是:当data
为obj
或'a
以及为什么p
的类型为{{1}时,为什么“缩短”的currying不起作用当'a -> unit
是data
时?
答案 0 :(得分:3)
所以我认为问题在于F#似乎是在错误的点上推广(从你的角度来看):
以下是您的代码版本,乍一看不应该进行类型检查:
let exec (f:unit -> unit) (data:obj) = f();;
let p:int -> unit = exec (fun () -> ());;
这似乎很奇怪int <> obj
。
此外,这是一个更简单的例子,它显示了你的行为(来自修改的规范)
type Base() =
member b.X = 1
type Derived(i : int) =
inherit Base()
member d.Y = i
let exec (f:unit -> unit) (data:Base) = f();;
let p = exec (fun () -> ());;
产生值限制错误。
这使得更清楚的是,当F#在函数调用之前插入隐式向上转换时,代码在函数中是有效的,但是一旦使它成为显式值,就不能使用此强制转换。
如果您希望编译代码,则需要通过添加类型注释来移动upcast的位置:
let exec (f:unit -> unit) (data:obj) = f()
let p:obj -> unit = exec (fun () -> ());;