为什么用obj来讨论不起作用?

时间:2013-08-18 10:29:54

标签: f#

你能解释为什么一个有效而另一个无效吗?

鉴于

//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,例如stringlong等。

这不起作用

//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参数的类型。 当它是objSystem.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

所以问题是:当dataobj'a以及为什么p的类型为{{1}时,为什么“缩短”的currying不起作用当'a -> unitdata时?

1 个答案:

答案 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 () -> ());;