是的,它可能会很有用。事实上,它的所有稍微不兼容的版本都会很有用!这有点问题。
甚至不清楚这样一个类意味着什么,这使得它很难实际使用,因为不可避免地你会遇到有多个默认值选择的类型,如果不能立即清楚实例提供了哪一个,那么你很漂亮很多人首先失去了上课的所有好处。
几个例子:
例如Monoid
,您显然希望标识元素是默认值。但是现在你又回到了具有两个或更多合理Monoid
实例的这么多类型的问题上。默认是Integer
0 还是 1?对于Monoid
,标准库使用newtype
包装器,但这些包装器很笨拙,并且很难使用包装器类型 -Monoid
它可以正常工作,因为您可以访问mconcat
等等,但是您不能仅使用默认值来做任何有趣的事情。
对于Functor
具有“空”值的 -like 类型,这给出了明显的默认值。这就是正在做的事情......MonadPlus
并且Alternative
也与 重叠Monoid
,如果记忆对我有用,那么至少有一种类型,这三个实例并不相同。当有多个选择时,你会选择哪一个?考虑列表:您可以盲目地附加它们,给一个任意的Monoid
,以空列表作为标识;但是对于你的列表,Monoids
你也可以zipWith mappend
,给出一个提升的幺半群repeat mempty
作为身份。许多仿函数有类似的Monoid
实例,但并不总是两者兼有——所以无论你选择哪个列表,你都会在概念上与其他一些不一致Functor
!
对于像这样的单位类型()
,选择默认值并不难!但是枚举呢?选择第一个构造函数有意义吗?有时,但并非总是如此。使用该课程的人将如何知道?
怎么样Bounded
?如果以上都不适用,您可以使用minBound
. 但是上面的一些类型也可以Bounded
,所以如果它们的默认值不是它们的最小值,你会混淆问题。
基本上,有足够多的重叠似乎是有道理的......但实际上,您至少已经想到了三种不同的类型类,并且尝试统一它们可能不像最初看起来那么有用。
如果您可以更好地确定事情并给出“默认”值的清晰、一致的语义解释,而无需重新发明Monoid
或另一个现有的类,这样类型类就易于使用,而无需停下来思考“默认”被选中,太棒了!但我不希望让它发挥作用。
也就是说,任何标准类型类都没有涵盖的一个明显合理的情况是像()
. 大多数情况下,这些并不是很有用——原因很明显!——这可能就是为什么没有这样的课程。但是,这样一个类非常有用的一个地方是,当你在做一些涉及类型级别恶作剧的事情时,因为这样的类型在类型和术语级别上都代表一个值——所以这样的类型的类可以让你自由操作类型级别的值,然后想出与之相关的术语,因此您可以将其传递给其他函数,例如,基于它选择类型类实例。出于这个原因,我在我的永远不完整的类型黑客库中有一门类似的课程,例如:
class TermProxy t where
term :: t
-- This makes explicit the lexical pun of () having type ().
instance TermProxy () where
term = ()
instance (TermProxy a, TermProxy b) => TermProxy (a, b) where
term = (term, term)
不过,我怀疑这样的课程在任何其他情况下都非常有用。