在下面的代码中,我定义了两个接口,第二个接口将第一个接口作为类型参数。但是代码会给出错误"类型参数' 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;是一个字符串,但我仍然必须声明它。我想知道为什么会出现这种情况,是否有解决方法而没有指定第二个类型参数。
答案 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() }
在这里你可以看到,当使用对象表达式时,可以推断出两个参数。