使用新成员覆盖类实例

时间:2011-12-15 02:50:03

标签: haskell typeclass

假设我有一个简单的类AClass,其公共成员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的{​​{1}}包装替换它,但唯一不可变的是上面的代码是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                       

3 个答案:

答案 0 :(得分:9)

你想要达到什么目标?

您有一个Val类型,您可以将其设为AClass的实例。您可以定义使用与该类无关的Val的任意数量的函数。只需停止尝试在instance声明中定义它们。

如果您期望能够拥有一个具有额外AClass函数的f2的特定实例,那么您可以在使用AClass个实例的函数中使用该实例。让他们能够致电f2 ......那太荒谬了。根据定义,所有AClass个实例都知道的唯一事物是AClass中声明的事物。如果您对某些值的了解是它是AClass实例类型的成员,那么您无法对AClass的所有实例执行任何操作。 。你不能再调用任何额外的特定事件。

如果您要创建一个 new 类,该类支持AClass执行的所有操作以及f2,并且Val是一个实例那个新班级...然后你就这样做了。

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

instance AnotherClass Val where
    f2 x = 0.0

答案 1 :(得分:5)

你的问题在Haskell中没有意义:

  

假设我有一个简单的班级AClass,其公开成员f1可以被覆盖。

如果您正在考虑“可以”覆盖“公共成员”的“课程”,那么您正在考虑面向对象的术语。您展示的代码根本不代表这些概念。请参阅Tony Morris的帖子"Type-classes are nothing like interfaces."

类型类定义概念(在C++ sense中,如果有帮助的话)。该概念由一些函数组成,例如:

class Eq a where 
  (==) :: a -> a -> Bool

...但没有这些功能的实际行为或实现。这里没有什么可以“覆盖”的。 model 这个概念的数据类型将提供实例声明,例如:

data Integer = {- ... -}
instance Eq Integer where 
  x == y =  x `integerEq` y

data Float = {- ... -}
instance Eq Float where
  x == y =  x `floatEq` y

所以你可以实现像:

这样的多态算法
allEqual :: Eq a => a -> a -> a -> Bool
allEqual a b c = (a == b) && (b == c)

现在,回到您的问题,您还可以定义模型更具体的概念的类型类,而不是某些先前定义的类型类。例如:

class (Eq a) => Num a where
  (+), (-), (*) :: a -> a -> a

因此,有些Eq的实例不是Num的实例,但Num的所有实例都必须是Eq的实例。在您的示例中,您可能需要以下内容:

class AClass a where
  f1 :: a -> Int

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

data Val = {- whatever -}
instance BClass Val where
  f1 _ = 0
  f2 _ = 0.0

同样,Val本身不是“继承好东西”,它只是说它是BClass的一个实例,因此也是AClass的一个实例。但这显然是玩具代码......

答案 2 :(得分:4)

你应该记住,Haskell不是面向对象的,Haskell类型类与面向对象意义上的类不太相似。

您只需定义一个函数f2 _ = 0.0即可。它不会是类型类AClass的成员,除非你将它添加到定义中 - 但为什么你需要它呢?