在Haskell中继承数据类型?

时间:2013-12-20 03:39:34

标签: haskell

是否可以继承haskell中的数据类型?让我们假设:

data Data1 = Data1
    { name :: String
    } deriving (Show)

在同一个模块上,我想做类似的事情:

data Data2 = Data1 
let x = Data2 "Something"

我希望Data2有字段name,'继承'来自Data1

我知道data Data2 = Data1没有做到这一点。所以,我想知道是否有办法做到这一点。

谢谢

安德烈

2 个答案:

答案 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

现在我们可以在nameD1上使用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}}

这是一种逆变子类型。