f#中的嵌套泛型类型推断

时间:2016-10-25 14:21:09

标签: f#

在下面的代码中,我定义了两个接口,第二个接口将第一个接口作为类型参数。但是代码会给出错误"类型参数' a'未定义"。

type IFirst<'a> = 
    abstract Data : 'a

type ISecond<'First when 'First :> IFirst<'a>> = 
    abstract First : 'First
    abstract SomeData : 'a

我的问题是为什么不能推断出什么类型&#39; a&#39;是从ISecond派生的,因为信息嵌入在&#39; First&#39;? 例如,在以下代码中,编译器可以推断出&#39; a&#39;是一个字符串。

type First () =
    interface IFirst<string> with
        member x.Data = ""

type Second () =
    interface ISecond<First> with
        member x.SomeData = ""
        member x.First = First()   

有没有办法解决这个问题,或者ISecond是否必须采用两种类型参数?

编辑:我知道ISecond可以使用两个类型参数(请注意我最初问题的最后一行)。为了更清楚我的意思,请考虑以下代码

type IFirst<'a> = interface end

type ISecond<'First, 'a when 'First :> IFirst<'a>> = interface end

type First () =
    interface IFirst<string> 

type Second () =
    interface ISecond<First, int> 

它给出了错误&#34;这个表达式应该有类型字符串,但这里有类型int&#34;,这意味着编译器知道&#39; a&#39;是一个字符串,但我仍然必须声明它。我想知道为什么会出现这种情况,是否有解决方法而没有指定第二个类型参数。

2 个答案:

答案 0 :(得分:4)

您对ISecond的定义不正确:您提到某种类型'a,但没有定义它。换句话说,ISecond实际上有两个通用参数 - 'First'a,但您只定义了其中一个。

这样可行:

type ISecond<'a, 'First when 'First :> IFirst<'a>> = 
    abstract First : 'First
    abstract SomeData : 'a

但是,当然,您还需要修改Second的定义:

type Second () =
    interface ISecond<string, First> with
        member x.SomeData = ""
        member x.First = First()  

答案 1 :(得分:3)

我认为你已经把两个不同的问题混为一谈了。一个是:

  

类型定义的通用参数都需要显式吗?

答案是肯定的。这与类型推断无关,它只是类型定义在F#中的工作方式 - 类型参数'a只能作为IFirst<_>的参数使用,如果它也是ISecond的参数{1}}。

另一个问题是:

  

编译器在定义子类型时可以推断出超类型的参数吗?

在这里,答案稍微有点微妙。定义类类型时,答案是指定所有类型参数的语法要求。如果你尝试这样的话:

type Second() = interface ISecond<First,_> with ...

您将收到错误消息

error FS0715: Anonymous type variables are not permitted in this declaration

但是,还有其他上下文可以毫无问题地推断出参数:

let second() = { new ISecond<_,_> with
                    member x.SomeData = ""
                    member x.First = First() }

在这里你可以看到,当使用对象表达式时,可以推断出两个参数。