目前我有以下数据类型:
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的显式性丢失了,我非常想保留它。
这可以实现吗?
答案 0 :(得分:2)
您似乎希望将单个类型构造函数Column
定义为
data Column a = Column String [a]
然后
sumColumn :: Column Double -> Column Double -> Column Double
sumColumn (Column name values) = ...
要区分原始版本中的StringColumn
和UnknownColumn
,请使用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
,并且您可以互换使用NumCol
和Column
。例如:
colFunction :: Column -> Column
colFunction = ...
变为
colFunction :: Columnlike a => a -> a
colFunction = ...
然后您可以在colFunction
和NumCol
上使用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上运行的每个函数。