使用新成员覆盖类实例

Sal*_*Sal 3 haskell typeclass

假设我有一个简单的类AClass,其公共成员f1可以被覆盖.有什么方法可以定义AClass与另一个成员的新实例,f2AClass不是复制源代码?玩具代码如下:

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 
Run Code Online (Sandbox Code Playgroud)

我环顾四周,但没有找到任何关于如何做到这一点的明确例子(即我能理解的例子 - 清晰度是相对的).有什么可能的方法?关闭,新类型声明或其他什么?用上面的玩具代码演示技术会很有帮助 - 你可以改变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                       
Run Code Online (Sandbox Code Playgroud)

Ben*_*Ben 9

你想要实现什么目标?

你有一个类型Val,你做了一个实例AClass.您可以定义任何Val与该类无关的函数.只是停止尝试在instance声明中定义它们.

如果你期望的是能够让一个特定的实例AClass具有额外的f2功能,那么你可以在使用AClass实例的函数中使用它们并让它们能够调用f2......这是荒谬的.根据定义,所有AClass实例都知道的唯一事物是声明的事物AClass.如果你所知道的某些值是它是一个类型的成员AClass,那么你就无法对它做任何事情AClass.您无法调用特定于某些实例的额外内容.

如果你想创建一个新的,支持所有的操作类AClass确实还有f2,和有Val是新的类的实例...那么你只要做到这一点.

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

instance AnotherClass Val where
    f2 x = 0.0
Run Code Online (Sandbox Code Playgroud)


mer*_*ict 5

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

假设我有一个简单的类AClass,其公共成员f1可以被覆盖.

如果你正在考虑"可以"覆盖"公共成员"的"课程",那么你就是在面向对象的术语中思考.您展示的代码根本不代表这些概念.请参阅Tony Morris的文章"Type-classes与接口类似."

型类定义了一个概念(在C++感,是否有帮助的话).该概念由一些函数组成,例如:

class Eq a where 
  (==) :: a -> a -> Bool
Run Code Online (Sandbox Code Playgroud)

......但没有这些功能的实际行为或实施.这里没有什么可以"覆盖"的.模拟此概念的数据类型将提供实例声明,例如:

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

data Float = {- ... -}
instance Eq Float where
  x == y =  x `floatEq` y
Run Code Online (Sandbox Code Playgroud)

所以你可以实现多态算法,如:

allEqual :: Eq a => a -> a -> a -> Bool
allEqual a b c = (a == b) && (b == c)
Run Code Online (Sandbox Code Playgroud)

现在,回到您的问题,您还可以定义类型类,这些类型类比以前定义的类型类更具体.例如:

class (Eq a) => Num a where
  (+), (-), (*) :: a -> a -> a
Run Code Online (Sandbox Code Playgroud)

因此,有些实例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
Run Code Online (Sandbox Code Playgroud)

再说一遍,Val不是"继承好东西"本身,它只是说它是一个实例,BClass因此也是一个实例AClass.但这显然是玩具代码......