Haskell 用新成员重写类实例
假设我有一个简单的类Haskell 用新成员重写类实例,haskell,typeclass,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 mem
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
我环顾四周,但没有找到任何关于如何做到这一点的清晰示例(例如,我能很好理解的示例-清晰性是相对的)。可能的方法是什么?闭包、新类型声明还是其他什么?使用上述玩具代码演示该技术将很有帮助-您可以更改数据
声明等(例如,用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
您应该记住,Haskell不是面向对象的,Haskell类型类也不太像面向对象意义上的类
您只需定义一个函数f2=0.0。除非将其添加到定义中,否则它不会成为typeclass AClass的成员——但为什么需要它呢?您想实现什么 您有一个类型
Val
,它是AClass
的一个实例。您可以定义任意数量的使用Val
且与类无关的函数。停止在实例
声明中定义它们
如果您期望的是能够拥有一个具有额外的f2
函数的AClass
实例,那么您可以在使用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
你的问题在Haskell中没有真正意义: 假设我有一个简单的类
AClass
,其中有一个公共成员f1
,该成员可以被覆盖
如果您考虑的是具有可以“重写”的“公共成员”的“类”,那么您考虑的是面向对象的术语。您展示的代码根本不代表这些概念。见托尼·莫里斯的帖子
类型类定义了一个概念(在中,如果有帮助的话)。该概念由一组功能组成,例如:
class Eq a where
(==) :: a -> a -> Bool
class (Eq a) => Num a where
(+), (-), (*) :: a -> a -> a
。。。但是没有这些功能的实际行为或实现。这里没有什么可以“重写”的。为该概念建模的数据类型将提供实例声明,如:
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 where
(==) :: a -> a -> Bool
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
的一个实例。但这显然是玩具代码…谢谢。澄清一下,我不是从面向对象的角度来问这个问题。问题是关于Haskell中有什么可能,以及如何实现。是的,一个支持AClass操作并执行f2的类将如何工作。但是,如果我尝试你的方法,我会得到一个错误,f1不是另一个类的可见成员。f1和f2的实现都留待实例处理,这就是错误的来源。类AClass a=>另一个类a,其中…
表示类型a
必须是AClass
的实例,才能成为另一个类的实例。如果您没有做出这样的声明,那将是您的错误。@sal您真的打算用不同的f2
实现另一个类的多个实例吗?如果它只是Val
,那么直接在Val
上实现f2
并使用Val
而不是AClass
键入其他代码会简单得多。如果已知Val
是它的一个实例,您仍然可以使用AClass
功能。@Ben,我计划有几个实例声明,每个声明都提供各自的f1和f2实现。很好地了解了OP的OOthinking@mergeconflict是的,用你的话来说,我想,“模型比以前定义的类型类更具体的概念”。您发布的最后一段代码与解决此问题有关(与Ben发布的代码类似)。问题是我无法在Val的实例声明中实现f1,因为编译器抱怨f1不是BClass的可见成员。那么,我们如何让实例声明实现f