构造函数作为Haskell中的数据类型

时间:2018-04-09 12:09:54

标签: haskell

目前我有以下数据类型:

data NumberColumn = NumberColumn String [Double]
data StringColumn = StringColumn String [String]
data UnknownColumn = UnknownColumn String [String]

所有这些数据类型(还有其他数据类型,这些只是域示例)模型csv文件列。它们可以代表普通数字,名称,金钱,简单文本等。

我想要达到的目标是:

data Column = NumberColumn String [Double] | StringColumn String [String] | UnknownColumn String [String]

也就是说,我想将它们放在一个数据类型中,这样就可以映射,过滤和创建新项目,如下所示:

sumColumn :: NumberColumn -> NumberColumn -> NumberColumn
sumColumn...

问题是NumberColumn不是数据类型而是构造函数,所以我能想到的最好是接受并返回Column类型:

sumColumn :: Column -> Column -> Column
sumColumn (NumberColumn...) (NumberColumn...)...

这样可行,但函数应该只接受NumberColumns的显式性丢失了,我非常想保留它。

这可以实现吗?

3 个答案:

答案 0 :(得分:2)

您似乎希望将单个类型构造函数Column定义为

data Column a = Column String [a]

然后

sumColumn :: Column Double -> Column Double -> Column Double
sumColumn (Column name values) = ...

要区分原始版本中的StringColumnUnknownColumn,请使用Unknown的新类型将其与“普通”字符串区分开来。

newtype Unknown = Unknown String

type UnknownColumn = Column Unknown  -- for example

答案 1 :(得分:0)

您可以将NumberColumn构造函数的数据分解为一个新的数据类型:

data Column
    = NumberColumn  NumCol
    | StringColumn  String [String]
    | UnknownColumn String [String]

data NumCol = NumCol String [Double]
然后,

sumColumn仅定义在NumCol s上,而不是Column s或NumberColumn s:

sumColumn :: NumCol -> NumCol -> NumCol
sumColumn (NumCol s1 d1) (NumCol s2 d2) = ...

编辑:

如果您希望NumCol的行为类似于NumberColumn,则可以使用类型类:

class Columnlike a where
    toColumn :: a -> Column

instance Columnlike Column where
    toColumn = id

instance Columnlike NumCol where
    toColumn = NumberColumn

有了这个类型类,您Column以上的函数现在可以超过Columnlike a,并且您可以互换使用NumColColumn。例如:

colFunction :: Column -> Column
colFunction = ...

变为

colFunction :: Columnlike a => a -> a
colFunction = ...

然后您可以在colFunctionNumCol上使用NumberColumn

答案 2 :(得分:0)

除了chepner的

data Column a = Column String [a]

您可以将sumColumn定义为

sumColumn :: Num a => Column a -> Column a -> Column a
sumColumn (Column name1 ms) (Column name2 ns) =
  Column (name1 ++ "+" ++ name2) (zipWith (+) ms ns)

您还可以使用GADT确保包含数字的列仅用于:

{-# LANGUAGE GADTs #-}

data Column a where
  NumColumn :: Num a => String -> [a] -> Column a
  StrColumn :: String -> [String] -> Column String

但你仍然必须限制在Num a => Column a s上运行的每个函数。