typeclass方法中的typeclass约束是不鼓励的吗?
我知道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
类型的约束不同,它实际上根本没有任何用途( data
的实现仅仅是一些数据布局,它不可能需要任何类的任何方法†)。
但是,可以通过在类头中包含额外的约束类型变量来避免此问题:
class (Eq b) => Foo b a where
foo :: a -> b
有时候,这比你的提议更好,但有时候它不会更好,例如Foo
有很多方法,而且这些方法只有一个与b
有关。 当然,在这种情况下,也可以将foo
分解成一个头部为b
的子类,并将其他方法留在一个类中,而不受其他约束。 但是有两个班而不是一个班也可能不太好。
因此,如果您发现自己处于这种情况是很自然的事情,那么我认为向类方法添加约束是完全合理的。
具有这种约束的方法的现有示例是foldMap
, traverse
和lift
。 这不是一个无处不在的模式,但绝对不是非常罕见的。
†如果考虑类型/数据族,这看起来有点不同,但即使这样,您不需要对data
约束,只需要处理这些数据的函数。
上一篇: Is a typeclass constraint discouraged in a typeclass method?
下一篇: What is the difference between traits in Rust and typeclasses in Haskell?