我已经在F#编程了好几年了,有一个“问题”困扰了我一段时间而且我无法解决。这不是一个错误,我认为这是一个设计决定,但无论如何,问题是:有没有办法延迟(可能这不是正确的话)接口的实现?,即没有实现它们在初始定义中,但稍后,也许在我为该类型实现模块后的同一文件中。我将用一个简单的例子来解释: 假设我有以下数据结构:
type 'T MyCollection =
(*type definition*)
interface IEnumerable<'T> with
member this.GetEnumerator () =
(* I don't want to implement it here
because I still don't have the module
with a toSeq function *)
如果我在那里实现了方法,我还必须将所有函数实现为类型的方法,然后模块将只是调用方法的“代理”。这样我就可以创建一个OO优先数据结构,然后创建一个模块(重载了类型注释),以便实现功能优先使用。我更愿意编写一个功能优先的数据结构(更清晰,因为类型推断可以更好地工作),然后创建一个OO包装器,以便为C#等语言提供更好的智能感知支持。这种方法符合F#的设计指南告诉我们的内容,但接口不能在任何地方实现,只能在类型的初始定义中实现。这种限制迫使我用成员编写整个数据结构。 我一直在寻找示例,我发现FSharp.Core list中的列表实现正是我想要的,但我不能这样做,编译器不会让我。 我几乎可以肯定这是一个设计决定,也许是为了避免鼓励不良做法,我不知道,但我不认为我希望成为一个糟糕的做法。我也很清楚fsharp编译器的线性特性。
如果你们中的任何一个人知道如何做我想做的事,如果你告诉我,我会很高兴的。此外,如果你们中的任何人知道为什么我不应该遵循这种方法,我也会很高兴知道。必须有一个原因,为什么这对其他任何人都不是问题。
提前致谢。
答案 0 :(得分:9)
我完全同意这是一个不幸的问题。 F#Core库中'a list
源代码中使用的技巧是在类型扩充中定义接口的实现。当您以这种方式向类型添加成员时,编译器不会抱怨,但它表示不推荐以这种方式添加接口的实现。但是,它不会阻止您这样做。以下编译对我来说很好:
open System.Collections
open System.Collections.Generic
type MyCollection<'T> =
{ Data : 'T list }
interface IEnumerable<'T>
interface IEnumerable
let getEnumerator { Data = d } =
(d :> seq<_>).GetEnumerator()
type MyCollection<'T> with
interface IEnumerable<'T> with
member this.GetEnumerator() = getEnumerator this
interface IEnumerable with
member this.GetEnumerator() = (getEnumerator this) :> _
这个被弃用的事实有点不幸。我非常喜欢这种风格,当它有意义时我会使用它。您可以start a discussion about this on F# user voice,也许可以将其恢复为正常接受的功能: - )