首页 文章

如何使F#推断共同基类型?

提问于
浏览
4

考虑一下:

module Module1 =
    type A() = class end
    type B() = inherit A()
    type C() = inherit A()

    let f x = if x > 0 then new B() else new C()

最后一行产生关于预期类型B的错误,但是找到了类型C.好吧,我可以假装理解:编译器不知道在有多少公共基础的情况下推断出来 .

但猜猜怎么了?即使我指定了函数类型,它仍然不起作用:

let f x : A = if x > 0 then new B() else new C()

现在这给了我两个错误:“A预期,B找到" and " A预期,C找到” . WTF?为什么不能看到B和C都可以隐式转换为A?

是的,我知道我可以使用 upcast ,就像这样:

let f x : A = if x > 0 then upcast new B() else upcast new C()

但猜猜(又一次)? upcast 仅在显式函数类型声明的情况下有效!换句话说,这个:

let f x = if x > 0 then upcast new B() else upcast new C()

仍然给出错误 .

WTF?为了帮助编译器,我真的必须在程序中添加50%的噪音吗?关于F#代码干净无噪音的炒作是什么?

不知怎的,感觉这不可能是真的 . 所以问题是:我错过了什么吗?如何使这既紧凑又有效?

2 回答

  • 2

    所有这一切都有一个原因,但要缩短:F#比C#更强大,所以你必须告诉在哪里投(见here):

    let f x = if x > 0 then (new B() :> A) else (new C() :> A)
    

    在这里您可以找到更多信息:F# need for cast

    这是另一个伟大的discussion .

  • 10

    类型推断和子类型不能很好地结合在一起,因为Carsten的链接在某种程度上进行了讨论 . 听起来你对F#的方法不满意,如果是的话会更喜欢它

    if b then 
        e1 
    else 
        e2
    

    被隐含地对待更像

    if b then (e1 :> 'a) else (e2 :> 'a)
    

    与编译器另外推断 'a 是类型层次结构中的最小上限,基于否则将推断 e1e2 的类型 .

    在技术上可能这样做,我可以这样工作,但是这里有一个猜测:如果 if 语句以这种方式运行,那么在 ifelse 分支中使用不同类型永远不会出错,因为它们可以总是通过隐式地将它们向上转换为 obj 来统一 . 但是,在实践中,这几乎总是一个程序员错误 - 你几乎总是希望类型是相同的(例如,如果我从一个分支返回一个字符而另一个字符串返回一个字符串,我可能意味着从两个字符串返回字符串,而不是 obj ) . 通过隐式向上转换,您只会更难找到这些错误 .

    此外,它正在寻找比 upcast 语法更短的解决方案,您可以尝试使用 :> _ ,只要存在约束类型的东西(整体结果上的注释或其中一个分支上的特定强制转换) ) .

相关问题