未知需要类型注释或强制转换

Dan*_*iel 2 f# type-inference

我知道我必须遗漏一些非常明显的东西.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() = ()
Run Code Online (Sandbox Code Playgroud)

我刚刚发现这个有效: (B.GetInstance() :> B).Call()

知道为什么演员是必要的吗?

kvb*_*kvb 7

通常,当你有一个递归的方法集来推断其类型时,F#需要帮助.一个更令人愉快的选择是注释定义B.GetInstance:

type A() =
  member x.Call() = B.GetInstance().Call()

and B() =
  static member GetInstance() : B = new B()
  member x.Call() = ()
Run Code Online (Sandbox Code Playgroud)

我相信你遇到这个问题的原因是F#试图同时解决A和B中所有方法的所有推断类型(因为它们被定义为相互递归类型),这会导致问题,但也许是来自F#的人团队将权衡.


Bri*_*ian 7

快速摘要是在一个递归组中(例如,一种类型的成员,或者像我们这里一样的递归类型的成员)F#以从左到右的从上到下的顺序读取声明,然后是左边的定义 -从右到上的顺序.因此,在这个实例中,当它达到定义时A.Call,它还没有读取定义,B.GetInstance因此(但是!)知道返回类型GetInstance将是B.

Keith的回答指出了这种情况,你可以提供一个类型注释来指定GetInstance其声明中的返回类型.

看到

强制泛型和接口上的F#类型推断保持松散

深入讨论这里发生了什么.

另请注意,在原始尝试中,您不需要"强制转换"(使用潜在的动态操作:>),而只需"注释"(静态声明类型,使用:)以使其进行编译.但更有意义的是将类型注释放在方法声明中GetInstance(通常,更喜欢对方法签名添加注释而不是在主体内部的任意位置).