首页 文章

静态分辨的类型参数

提问于
浏览
4

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

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给出了以下错误: The type 'BTy' does not support any operators named 'MyMember' .

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

2 回答

  • -1

    说实话,我有点惊讶你甚至被允许在类型声明中使用静态成员约束,但正如@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) ()) }
    

    例如,该函数将从 BTy 类型创建 IMyMember

    /// 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,我认为它在那里非常好用 .

  • 11

    你的实现@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 }
    

相关问题