为什么Data.FingerTree有一个类型类Measured而不仅仅是一个函数



我不明白为什么FingerTree是用类型类Measured实现的。

我试图实现一个具有与monoid相同的默认度量的monoid序列,所以我写了以下内容。

instance Monoid a => Measured (Sum Int, a) a where
  measure x = (Sum 1, x)

当然,由于FingerTree本身就是Measured,这是不可能的,因为我们会得到类型类重叠。

把这个函数抽象成一个类型类在什么时候有意义?为什么我们不能只定义FingerTree,这样我们就可以向构造函数提供度量函数?

如果能知道是否有办法克服这个问题,那也太好了。我可以每次为我的特定用例定义一个新实例,但也许有更好的方法。

这是typeclass函数解析和"直接"函数解析之间的一般摩擦的一个例子。正如您在这里指出的,有很多时候支持直接,但通常情况下,当可以声明类型类实例必须遵守的特定法律时,人们会发现使用类型类解析是有意义的。

我认为不可能有一个"正确"的答案,哪一个更好,但确实有很多理由更频繁地使用直接方法。

在这种情况下,需要更多的特殊性来帮助编译器了解应该解析哪个实例。虽然任何Monoid都可以有一个"计数并组合"Measured实例,但尚不清楚这是否是规范实例。由于Measured的类要求Measured v a | a -> v,所以我们必须规范地选择v

最可能的方法是创建一个newtype包装

newtype Counted a = Counted a
instance Monoid a => Measured (Sum Int, a) (Counted a) where
  measure (Counted x) = (Sum 1, x)

这给了我们必要的规范性。在某些情况下,此可能比直接传递Monoid函数字典更方便。

相关内容

最新更新