是否可以继承haskell中的数据类型?让我们假设:
data Data1 = Data1
{ name :: String
} deriving (Show)
在同一个模块上,我想做类似的事情:
data Data2 = Data1
let x = Data2 "Something"
我希望Data2
有字段name
,'继承'来自Data1
。
我知道data Data2 = Data1
没有做到这一点。所以,我想知道是否有办法做到这一点。
谢谢
安德烈
答案 0 :(得分:5)
Haskell没有继承。事实上,从你的脑海中消除所有与OOP相关的想法。
相反,从构图角度思考是一种更富有成效的方法。
newtype Data1 = Data1 {name :: String}
deriving Show
newtype Data2 = Data2 {wrappedD1 :: String}
现在你可以拥有
nameD2 :: Data2 -> String
nameD2 = name . wrappedD1
但是,如果要对这两个操作使用相同的名称,则需要“ad-hoc多态”,即重载。在Haskell的土地上,我们有这个类型
data D1 = D1 {nameD1 :: String} deriving Show
data D2 = D2 {wrappedD1 :: D1} deriving Show
class Named a where
name :: a -> String
instance Named Data1 where
name = nameD1
instance Named Data2 where
name = name . wrappedD1
现在我们可以在name
和D1
上使用D2
。这类似于接口的概念。
Tangent:你使用顶层语法let foo = bar
但是在Haskell中,我们只在GHCi中使用let
绑定,因为GHCi的工作方式有些奇怪。而只使用foo = bar
。
答案 1 :(得分:2)
Haskell倾向于在结构子类型和“HAS-A”关系方面做得很好。继承Data1的最直接方法是使用newtype
newtype Data2 = Data2 { unData2 :: Data1 }
在这种情况下,Data2
已知与Data1
相同。实际上,在编译时Data2
将与Data1
相同。重要的是,如果Data2
选择,instances
将有机会定义完全唯一的类型Data1
。
除此之外,您可以在一些更复杂的“继承”数据类型中记录data DataMore =
DataMore { data1 :: Data1
, otherThing :: OtherThing
, somethingElse :: SomethingElse
}
。
Data1
现在,任何以DataMore
作为参数的内容都可以通过简单的扩展来取代-- given...
foo :: Data1 -> Data1 -> X
-- we have
fooMore :: DataMore -> DataMore -> X
fooMore dm1 dm2 = foo (data1 dm1) (data1 dm2)
。
{{1}}
这是一种逆变子类型。