是否有可能从类型/函数定义中重构​​泛型参数约束?

时间:2014-05-31 08:14:15

标签: .net f#

假设我有一个通用类型,其中包含一长串通用参数约束:

type Gen<'A when cond1 and cond2 and ...>(a:'A) =
    member this.A = a

此外,对于项目中的其他类型,会出现相同的约束列表。每次重复相同的约束列表会产生很多噪音。更糟糕的是,它阻碍了可扩展性和功能设计,因为作用于Gen.A的函数需要重新声明这些约束。 Gen的方法也是如此。

是否可以从类型定义中重构​​这些约束?这类似于在类型上创建一种类型或谓词。

编辑:具体案例如下,虽然这可能没有帮助。我有三个抽象类ProductViewerProducer。参数化是

Product<'Viewer> 
Viewer<'Product> 
Producer<'Product, 'Viewer where 'Product:> Product<'Viewer> and 'Viewer:>Viewer<'Product> and 'Viewer : (new : unit -> 'Viewer)>

这是最后一个让我烦恼的人。 Viewer会比较Product的不同实例,Producer会根据数据流生成产品,并将其添加到适当的Viewers。不同类型的产品是通过Product的继承完成的,相应的Viewers派生自Viewer。

这有点像clusterfuck但是我相信最简洁的方法是在不牺牲性能或静态类型检查的情况下完成它。例如,如果将Viewer的抽象方法从通用AddProduct: 'Product->unit更改为从抽象类中获取参数:AddProduct: Product->unit(并对其他方法进行类似修改),则可以抛弃整个通用结构。然而,这将使得人们可以向查看器添加错误类型的产品,并且它将仅在运行时抛出。

创建一个可以协同工作的类型的通用元组的这个问题我相信在NET中没有一个非常干净的解决方案。

2 个答案:

答案 0 :(得分:2)

F#中没有这样的机制。您可以通过使用静态工厂函数来限制需要了解约束的函数,该函数约束可以构造类的值,然后将依赖于约束的所有函数作为参数传递。在很多功能中确实需要参数约束的情况下,这显然有一些严重的缺点。这里可能还有其他选项,我认为所有这些选项最终都会成为需要类型约束的类部分的某种形式的隔离。

答案 1 :(得分:2)

看到像这样受限制的类型也会让我感到烦恼。这几乎是一个肯定的迹象,在设计的某个地方出了问题。

首先让我觉得奇怪的是为什么你需要一个Product<'Viewer>?我不希望产品知道关于观众的任何信息,所以在我看来,无论产品中的功能是什么,都会使用'Viewer,它可能生活在那种类型之外。

对我来说,第二件事就是作为类型约束存在的小事,是'Viewer : (new : unit -> 'Viewer)。如果您希望Producer能够创建Viewer的实例,您只需传入makeViewer: unit -> 'Viewer即可获得它。

有了这个,我想你可以轻松得到类似的东西:

Product 
Viewer<'Product> 
Producer<'Product, 'Viewer where 'Viewer:>Viewer<'Product>>

最后,如果您只关心IViewer界面,您可以使用以下内容:

Producer<'Product>(makeViewer: unit -> IViewer<'Product> ...)

并且类型的头痛更少。