在数据类型构造函数中使用类

时间:2012-08-08 06:29:18

标签: haskell

目前我有这样的事情:

data MyData = SomeData | MoreData | EvenMore
data DataLists = DataLists [MyData] [MyData]

这让我显然可以这样做:

myDataList :: DataLists
myDataList = DataLists [SomeData, MoreData] [EvenMore, SomeData]

但我想做一些像这样的事情:

-- Static Module File:

class MyClass b where
    evaluate :: b -> Int

data SomeData = SomeData
data MoreData = MoreData
data EvenMore = EvenMore

instance MyClass SomeData where
    evaluate _ = 2
instance MyClass MoreData where
    evaluate _ = 3
instance MyClass EvenMore where
    evaluate _ = 4

data DataList = DataList [MyClass] [MyClass] -- Obviously this is wrong

我希望我的代码中的那部分保持静态。因为稍后我想在某些类型中添加使用该模块放入数据列表。我需要这个单独的,因为整个模块将用于2个不同的项目,我不想继续编辑它。

data MyVeryOwnData = MyVeryOwnData
--I should be able to make up as many datastructures as I want

instance MyClass MyVeryOwnData where
   evaluate _ = 99

myList :: DataList
myList = DataList [MyVeryOwnData, SomeData] [SomeData, EvenMore]

我意识到我可以简单地将MyVeryOwnData放在模块文件中:

data MyData = SomeData | MyVeryOwnData ...

instance MyClass MyData where
    evaluate SomeData = 2
    evaluate MoreData = 3
    ... etc.

但是我不想那样做,因为我之前说过我想要添加任意数量的数据类型。

1 个答案:

答案 0 :(得分:6)

您正在寻找的是异构列表,而haskell主要通过两种方式支持它们,ExistentialsGADTs。我向您展示了一个可运行的代码示例,它解决了存在问题。

{-# LANGUAGE ExistentialQuantification #-}

class Eval b where
    evaluate :: b -> Int

data SomeData = SomeData
data MoreData = MoreData
data EvenMore = EvenMore

instance Eval SomeData where
    evaluate _ = 2
instance Eval MoreData where
    evaluate _ = 3
instance Eval EvenMore where
    evaluate _ = 4

data Evalable = forall a . Eval a => Evalable a

instance Eval Evalable where
    evaluate (Evalable a) = evaluate a

pack :: Eval a => a -> Evalable
pack = Evalable

data DataLists = DataLists [Evalable] [Evalable]

getFirst :: DataLists -> [Evalable]
getFirst (DataLists xs ys) = xs

main = do
  let dl = DataLists [pack SomeData, pack EvenMore] [pack MoreData]
  print . map evaluate . getFirst $ dl

应该很清楚,您可以在外部模块中添加instance Eval MyVeryOwnData,然后您可以pack这些值,使它们变为Evalable,然后您可以将它们放入{{1} }}