2

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

给定

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

所以问题是:为什么“快捷”currying 不起作用 when dataisobj'a为什么类型pis 'a -> unitwhen datawas obj

4

1 回答 1

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 () -> ());;
于 2013-08-18T10:48:08.967 回答