我知道在Haskell中不鼓励数据中的约束.例如,
data Eq b => Bar b = Bar b
没有弃用的扩展名是不可能的.我甚至也听到了
data Bar b = Eq b => Bar b
不常见,甚至气馁.(这是对的吗?)
对于类型类中的约束是否同样如此?例如,正在做类似的事情
class Foo a where foo :: Eq b => a -> b
在Haskell也气馁?它是否在常见代码中常见?
从使用角度来看,类型类方法与普通多态函数没有什么不同,普通多态函数恰好将该类作为对其参与者类型变量中的一个(或多个)的约束.但是签名中可能存在其他类型变量,这些变量需要不受一个类头提供的其他约束.为了能够实现函数,约束(通常)是必需的,因此,对类方法需要约束当然是合理的 - 不像data
类型的约束,它实际上根本没有用处(a的实现data
只是一些数据布局) ,它不可能需要任何类别的任何方法†).
但是,您可以通过在类头中包含额外的约束类型变量来避免此问题:
class (Eq b) => Foo b a where foo :: a -> b
有时候,这比你的提议更好,但有时它肯定不会更好,例如,如果Foo
有一大堆方法,而这些方法只有一个是关注的b
.当然,在这种情况下,也可以只分割foo
成一个b
在其头部的子类,并将其他方法保留在一个没有额外约束的类中.但是有两个班而不是一个班也可能不那么好.
因此,如果你发现自己处于一种自然而然的事情,我会认为在类方法中添加约束是完全合法的.
具有这种约束的方法的现有示例是foldMap
,traverse
和lift
.它不是普遍存在的模式,但绝对不是完全不常见的.
† 如果考虑类型/数据系列,这看起来有点不同,但即使这样,您也不需要约束,data
只需要处理这些数据的函数.