假设我有一个简单的类 AClass,它有一个可以被覆盖的公共(public)成员 f1。有什么方法可以用另一个成员 AClass 定义一个新的 f2 实例,而不是复制 AClass 的源代码?玩具代码如下:

class AClass a where
    f1 :: a -> Int

data Val = I Int

instance AClass Val where
  f1 x = 0

  -- the method below can't be added as it is not public member of AClass
  -- f2:: a -> Float
  -- f2 x = 0.0

我环顾四周,但没有找到任何关于如何做到这一点的明确示例(即,我可以很好地理解示例 - 清晰度是相对的)。有哪些可能的方法?关闭,新类型声明还是其他什么?使用上面的玩具代码演示该技术会很有帮助 - 您可以更改 data 声明等(例如,将其替换为 newtype 周围的 Int 包装器),但上述代码中唯一不可变的是 AClass 的类声明。这是因为假设该类已经由库作者编写,因此,我无法触及它。最终结果应该是另一个玩具代码,它继承了 AClass 的优点,并添加了 f2 成员。

当然,在像这样的覆盖类中会有一些警告。但是,它有助于了解什么是可能的,以及如何。

-- 更新 --

下面的工作代码 - 感谢 Ben 和 mergeconflict 提出解决方案 - 几乎没有遗漏的部分 - 填写如下:
class AClass a where
    f1 :: a -> Int

class (AClass a) => BClass a where
    f2 :: a -> Float

data Val = I Int

instance AClass Val where
   f1 _ = 0

instance BClass Val where
   f2 _ = 0.0

最佳答案

你想达到什么目的?

您有一个 Val 类型,它是 AClass 的一个实例。您可以定义任意数量的使用 Val 的函数,这些函数与类无关。停止尝试在 instance 声明中定义它们。

如果您期望能够拥有一个具有额外 AClass 函数的 f2 特定实例,然后您在使用 AClass 实例的函数中使用该实例并让它们能够调用 f2 ......那是荒谬的。根据定义,所有 AClass 实例唯一已知的东西是在 AClass 中声明的东西。如果您只知道某个值是 AClass 实例类型的成员,那么您无法对它执行任何操作,而不能对 AClass 的所有实例执行任何操作。您不能调用任何特定于某些实例的额外内容。

如果您想创建一个新类,该类支持 AClassf2 所做的所有操作,并且让 Val 成为该新类的实例……那么您只需这样做。

class AClass a => AnotherClass a where
    f2 :: a -> Float

instance AnotherClass Val where
    f2 x = 0.0

关于haskell - 用新成员覆盖类实例,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8514527/

10-10 22:52