静态分辨的类型参数

时间:2012-10-14 11:34:45

标签: 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 () = ()

当我定义字段AField(AField : A< BTy >)的类型时,IntelliSense给出了以下错误: “BTy”类型不支持任何名为“MyMember”的运算符

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

2 个答案:

答案 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 }