Is there such thing like “rigid type” in F#?
在Haskell类型类中可以引入"接口",其中有一些"自由"类型参数,例如"对于所有a:实例都支持此功能集"。而且,如果实例化此类类型类,则不能缩小此
1 2 | interface System.Collections.Generic.IEnumerable<byte> with member __.GetEnumerator () = (__.GetBytes ()).GetEnumerator () |
这正在编译,按我的预期工作,一切都很好。但是在这里,我做了一个更狭窄的接口:
您的代码段类似于Haskell实例,而不是Haskell类。该代码段说明,周围的类型是
我想这里的关键见解是必须将
在F#中,第一个参数是隐式的-接口声明中没有直接提及它,但是每个接口都有它-这是实现接口的类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // F# type MyType = MyType with interface IEnumerable<byte> with member this.GetEnumerator() = xyz -- Haskell class IEnumerable t e where getEnumerator :: t -> [e] data MyType = MyType instance IEnumerable MyType Byte where getEnumerator t = xyz |
在这里,很容易看到
F#不能做的一件事(就是这样)是为任何
1 2 | instance IEnumerable MyType e where getEnumerator t = ... |
要在F#中实现类似(但不完全相同)的效果,可以创建另一个接口并实现它:
1 2 3 4 5 6 7 8 9 10 11 | type AnyEnumerable = abstract member AnyEnumerate<'a>() : IEnumerable<'a> type MyType = MyType with interface AnyEnumerable with member this.AnyEnumerate<'a>() = { new IEnumerable<'a> with member this.GetEnumerator() = ... } let x = MyType.AnyEnumerate<int>() let y = MyType.AnyEnumerate<string>() |
在您的示例中,外部
如果您想指定一个开放的通用接口实现,那肯定是可能的(并且很常见)。您可以让类型实现类似
1 2 | type MyEnumerable () = interface IEnumerable<'Any> with ... |
,但是如果您在接口本身之外在类型本身上声明type参数,也可以执行以下操作:
1 2 | type MyEnumerable<'Any> () = interface IEnumerable<'Any> with ... |
这主要是由于F#起源于.NET,其中接口在泛型之前存在,并且与运行时如何使用类型紧密联系在一起,但是在其接口实现中将类型与类型参数断开连接通常总是没有任何意义的接口可能只具有非常有限的功能,或者会执行与类型本身无关的操作,无论如何这很可能是一个糟糕的设计。
现在,如果我回到您的示例,您可以尝试将