我不明白为什么FingerTree用类类实现Measured.
我正在尝试实现一个monoid序列,其默认度量与monoid相同,所以我写了以下内容.
instance Monoid a => Measured (Sum Int, a) a where
measure x = (Sum 1, x)
Run Code Online (Sandbox Code Playgroud)
当然,由于FingerTree它本身就是一个Measured,这是不可能的,因为我们将得到类型类重叠.
在什么时候将这个单个函数抽象为类型类是有意义的?为什么我们不能只定义FingerTree所以我们可以将一个度量函数提供给构造函数?
知道是否有办法克服这个问题也很好.我可以每次为我的特定用例定义一个新实例,但也许有更好的方法.
这是类型类函数解析和“直接”函数解析之间普遍摩擦的一个例子。正如您在这里指出的那样,很多时候都支持直接,但很多时候,当可以声明类型类实例必须遵守的特定法律时,人们会发现使用类型类解析是有意义的。
我认为不可能有一个更好的“正确”答案,但确实有很多理由支持更频繁地使用直接方法。
在这种情况下,需要更多的特异性来帮助编译器了解应该解析哪个实例。虽然任何情况都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)
Run Code Online (Sandbox Code Playgroud)
这给了我们所需的规范性。在某些情况下,这可能比直接传递Monoid函数字典更方便。