Types 静态解析类型参数

Types 静态解析类型参数,types,parameters,f#,Types,Parameters,F#,下面的(简化的)代码段取自我正在实现的一个应用程序,它始终使用静态解析的类型参数 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 () = () 当^B:(

下面的(简化的)代码段取自我正在实现的一个应用程序,它始终使用静态解析的类型参数

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 () = ()
当^B:(静态成员MyMember:Unit->Unit)时键入A<^B{
字段:单位
}
类型TestA={
外地:A
}
和BTy={
B场:单位
}与
静态成员MyMember()=()
当我定义字段AField(
AField:A
)的类型时,IntelliSense给了我以下错误:类型“BTy”不支持任何名为“MyMember”的运算符。

编辑。
单独声明它们是可行的,但是如果我有一个相互引用,并且我不能声明第三种类型放在顶部,它包含这两种类型的公共信息。我应该怎么做来避免这个问题?无论如何,如果我在下面定义
let pluto=(“”:>obj):?>A
它可以工作,我想这是因为这两种类型都可以从let绑定中看到。

老实说,我有点惊讶,你甚至可以在类型声明中使用静态成员约束,但正如@pad所提到的,当您按照正确的顺序放置声明并删除递归时,它就可以工作了(尽管我不确定当您转到更复杂的示例时是否会有其他限制):

现在,静态成员约束仍然可以用于从具有所需成员但未实现接口的类型创建接口的实现。使用此技术,您应该能够实现与类型上的静态成员约束完全相同的功能(但更清晰):


除此之外,我在一篇文章中使用了相同的技术,展示了如何使用它,我认为它在那里工作得非常好。

您的实现@Tomas满足了这个问题,但是对于您的解决方案的风格有一些犹豫,因为它不尊重函数式编程范式。我想到了一个由Haskell的类型类实现产生的解决方案。 接口、抽象类等的实现是为了让F#环境能够与.Net环境“交互”,因为风格的一致性——使用实现接口、抽象类等的代码。在不需要与.Net库交互的环境中,我认为这是一种“开销”(虽然F#是一种多范式语言)。这就是我发现Haskell类型类的实现非常优雅的原因。下面我通过F#实现了“Haskell类型类”代码来解决我的问题

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 }
类型操作<^a>=
{  
MyMember:unit->unit
}
键入A<^A>={
操作:操作<^a>
}
和TestA={
外地:A
}
和BTy={
B场:单位
}
让它=
让BTy_操作:操作={MyMember=fun()->()}
设A_of_BTy={Operations=BTy_Operations}
{AField=A_of_BTy}

这些类型的约束是允许的吗?这可能会导致各种互操作问题,比如说C#编译器无法实现它们。此外,从文档页面上看,
不能用于类型。
用于静态解决。有什么理由不单独声明它们吗?例如,
类型A
,然后
类型BTy
,然后
类型TestA
?@JohnPalmer
静态
成员约束列在上,作为一个有效的示例。bytebuster是正确的。递归类型声明不能很好地处理静态约束。请将声明按顺序排列,它会工作。@bytebuster-但请检查静态解析页面-它说不能用于类型这看起来像这也是一个很好的解决方案。它需要比使用静态约束捕获
MyMember
实现的实现更多的输入(您必须在
BTy\u操作中填充实现)但请记住,F#不是Haskell。F#是一种多范式语言,它的设计允许在有意义时将面向对象的概念(如接口)与函数概念(如记录)混合。F#不支持Haskell样式的类型类,因此人们使用不同的编程模式rns用于解决您在Haskell中使用类型类解决的问题。尝试模仿在Haskell中工作的解决方案不会给出惯用的F#代码。
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) ()) }
/// A type that contains field and a captured implementation of 'IMyMember'
type A = 
  { Field : unit 
    Operations : IMyMember } 

let it = { Field = ()
           Operations = captureMyMember<BTy> }
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 }