以下(简化)摘录摘自我正在实施的应用程序,该应用程序始终使用静态解析的类型参数。
type A< ^B when ^B : (static member MyMember : Unit -> Unit)> = {
Field : unit
}
type TestA = {
AField : A< BTy >
}
and BTy = {
BField : Unit
} with
static member MyMember () = ()
当我定义字段AField(AField : A< BTy >
)的类型时,IntelliSense给出了以下错误: “BTy”类型不支持任何名为“MyMember”的运算符
编辑。
单独声明它们是有效的,但是如果我有一个共同引用并且我不能声明第三种类型放在顶部,它包含两种类型的公共信息。我该怎么做才能避免这个问题?无论如何,如果我定义下面定义let pluto = ("" :> obj) :?> A< BTy >
它的作用,我想是因为这两种类型都是从let绑定中可见的。
答案 0 :(得分:11)
老实说,我有点惊讶你甚至被允许在类型声明中使用静态成员约束,但正如@pad所提到的,当你按正确的顺序放置声明并删除递归时,它工作(虽然我不确定当你转向更复杂的例子时不会有其他限制):
type A< ^B when ^B : (static member MyMember : Unit -> Unit)> =
{ Field : unit }
type BTy =
{ BField : Unit }
static member MyMember () = ()
type TestA = { AField : A<BTy> }
无论如何,我认为在类型声明中使用静态成员约束有点复杂。更简洁的方法是定义一个清晰描述(和文档)所需成员的界面:
type IMyMember =
abstract MyMember : unit -> unit
现在,静态成员约束仍可用于从具有所需成员的类型创建接口的实现,但不实现接口。使用这种技术,您应该能够实现与对类型的静态成员约束完全相同的功能(但以更清晰的方式):
/// Captures 'IMyMember' implementation from another type using static constraints
let inline captureMyMember< ^B when ^B : (static member MyMember : Unit -> Unit)> =
{ new IMyMember with
member x.MyMember () =
(^B : (static member MyMember : Unit -> Unit) ()) }
例如,该功能会从您的IMyMember
类型中创建BTy
:
/// A type that contains field and a captured implementation of 'IMyMember'
type A =
{ Field : unit
Operations : IMyMember }
let it = { Field = ()
Operations = captureMyMember<BTy> }
除此之外,我在一篇展示如何write generic numeric code的文章中使用了相同的技术,我觉得它在那里很有效。
答案 1 :(得分:-1)
你的实现@Tomas满足了这个问题但是你对解决方案的风格有些犹豫,因为它不尊重函数式编程范式。我想到了一个由Haskell的Type Classes实现产生的解决方案。 已经实现了接口,抽象类等,以便允许F#环境与.Net环境“交互”,原因是样式的一致性使用在上下文中实现接口,抽象类等的代码。不需要与.Net库交互,在我看来它是一个“开销”(尽管F#是一种多范式语言)。这就是为什么我发现Haskell类型类的实现非常优雅的原因。下面我通过F#实现了“Haskell Type Class”代码来解决我的问题。
type Operations< ^a> =
{
MyMember : unit -> unit
}
type A< ^a> = {
Operations : Operations< ^a>
}
and TestA = {
AField : A< BTy >
}
and BTy = {
BField : Unit
}
let it =
let BTy_operations : Operations< BTy > = { MyMember = fun () -> () }
let A_of_BTy = { Operations = BTy_operations }
{ AField = A_of_BTy }