我知道我必须遗漏一些非常明显的东西。 B.GetInstance().Call()
生成错误:根据此程序点之前的信息查找不确定类型的对象。在此程序点之前可能需要类型注释来约束对象的类型。这可能允许解析查找。
我正在使用v1.9.9.9。
type A() =
member x.Call() = B.GetInstance().Call()
and B() =
static member GetInstance() = new B()
member x.Call() = ()
我刚刚发现这有效:(B.GetInstance() :> B).Call()
知道为什么演员必要吗?
答案 0 :(得分:7)
当你有一个递归的方法类型要推断时,F#经常需要帮助。一个更令人愉快的选择是注释B.GetInstance
:
type A() =
member x.Call() = B.GetInstance().Call()
and B() =
static member GetInstance() : B = new B()
member x.Call() = ()
我相信你遇到这个问题的原因是F#试图同时解决A和B中所有方法的所有推断类型(因为它们被定义为相互递归类型),这会导致问题,但也许有人来自F#团队的人将会权衡。
答案 1 :(得分:7)
快速摘要是在一个递归组中(例如,一种类型的成员,或者像我们这里一样的递归类型的成员)F#从左到右顶部读取声明最低订单,然后是从左到右从上到下的定义。因此,在这个实例中,当它达到A.Call
的定义时,它还没有读取B.GetInstance
的定义,因此(还没有!)知道返回类型GetInstance
将为B
。
Keith的回答指出了这种情况,你可以提供一个类型注释来在声明中指定GetInstance
的返回类型。
见
Forcing F# type inference on generics and interfaces to stay loose
深入讨论这里发生的事情。
另请注意,在原始尝试中,您不需要“强制转换”(使用:>
进行潜在动态操作),而只需“注释”(静态声明类型,使用{{ 1}})让它编译。但是将类型注释放在:
的方法声明中更有意义(通常,更喜欢对方法签名添加注释而不是在主体内的任意位置)。