我建议根本不要使用类型类。将您的操作定义为简单的数据类型:
data ShapeOps a =
ShapeOps {
intersect :: Maybe (a -> a),
refine :: Maybe (a -> a)
}
然后你可以使用存在量化:
data Shape =
forall a. Shape (ShapeOps a) a
这个概念更容易考虑:
data Shape =
forall a.
Shape {
intersect :: Maybe (a -> a),
refine :: Maybe (a -> a),
shape :: a
}
使用Maybe
只是一个例子。您还可以使用RankNTypes代替存在量化:
newShape ::
(forall a. (a -> a) -> a -> b) ->
(forall a. (a -> a) -> a -> b) ->
ShapeConfig ->
b
如果它有交集,这个函数可以将形状传递给第一个延续,如果它有细化,则传递给第二个延续。你可以想出各种组合方式。使用Monoid
或者Alternative
您甚至可以同时执行以下操作:
newShape ::
(Alternative f) =>
(forall a. (a -> a) -> a -> f b) ->
(forall a. (a -> a) -> a -> f b) ->
ShapeConfig ->
f b
使用 RankNTypes 的优点是您可以编写更灵活的函数。您现在可以拥有折叠、地图或任何您想要的东西,而不是简单的构造函数。