Haskell中作为数据类型的构造函数
目前我有以下数据类型:Haskell中作为数据类型的构造函数,haskell,Haskell,目前我有以下数据类型: data NumberColumn = NumberColumn String [Double] data StringColumn = StringColumn String [String] data UnknownColumn = UnknownColumn String [String] 所有这些数据类型(也有其他数据类型,这些只是域示例)都为csv文件列建模。它们可以表示普通数字、姓名、货币、简单文本等 我想要实现的是这样的目标: data Column =
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不是一个数据类型,而是一个构造函数,所以我能想到的最好方法是接受并返回列类型:
sumColumn :: Column -> Column -> Column
sumColumn (NumberColumn...) (NumberColumn...)...
这是可行的,但是函数应该只包含NumberColumns的明确性已经丢失,我非常希望保留它
这可以实现吗?您可以将
NumberColumn
构造函数的数据分解成新的数据类型,从而:
data Column
= NumberColumn NumCol
| StringColumn String [String]
| UnknownColumn String [String]
data NumCol = NumCol String [Double]
然后,sumColumn
仅在numcoln
s上定义,而不是Column
s或NumberColumn
s:
sumColumn :: NumCol -> NumCol -> NumCol
sumColumn (NumCol s1 d1) (NumCol s2 d2) = ...
编辑:
如果希望numcoll
s的行为类似于NumberColumn
s,可以使用类型类:
class Columnlike a where
toColumn :: a -> Column
instance Columnlike Column where
toColumn = id
instance Columnlike NumCol where
toColumn = NumberColumn
有了这个类型类,您的列
上的函数现在可以覆盖一些列,比如a
,并且您可以互换地使用numcoll
s和列
s。例如:
colFunction :: Column -> Column
colFunction = ...
变成
colFunction :: Columnlike a => a -> a
colFunction = ...
然后,您可以在
NumCol
s和NumberColumn
s上使用colFunction
。您可以将NumberColumn
构造函数的数据分解成新的数据类型,从而:
data Column
= NumberColumn NumCol
| StringColumn String [String]
| UnknownColumn String [String]
data NumCol = NumCol String [Double]
然后,sumColumn
仅在numcoln
s上定义,而不是Column
s或NumberColumn
s:
sumColumn :: NumCol -> NumCol -> NumCol
sumColumn (NumCol s1 d1) (NumCol s2 d2) = ...
编辑:
如果希望numcoll
s的行为类似于NumberColumn
s,可以使用类型类:
class Columnlike a where
toColumn :: a -> Column
instance Columnlike Column where
toColumn = id
instance Columnlike NumCol where
toColumn = NumberColumn
有了这个类型类,您的列
上的函数现在可以覆盖一些列,比如a
,并且您可以互换地使用numcoll
s和列
s。例如:
colFunction :: Column -> Column
colFunction = ...
变成
colFunction :: Columnlike a => a -> a
colFunction = ...
然后,您可以在
NumCol
s和NumberColumn
s上使用colFunction
。似乎需要一个定义为
data Column a = Column String [a]
然后
要将StringColumn
和UnknownColumn
与原始字符串区分开来,请为Unknown
使用一个新类型,以将其与“普通”字符串区分开来
似乎您需要一个单一类型的构造函数
列
定义为
data Column a = Column String [a]
然后
要将StringColumn
和UnknownColumn
与原始字符串区分开来,请为Unknown
使用一个新类型,以将其与“普通”字符串区分开来
除了切普纳的
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
但是,除了chepner的函数外,还必须约束在
numa=>列a
s上运行的每个函数。
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
但是,您仍然必须约束在
numa=>列a
s上运行的每个函数。这将起作用,但这是一个可读性问题。NumCol和NumberColumn是/代表同一事物,因此我非常希望有一个单一的名称。@PetrasPurlys那里可能没有免费的午餐。但是,您可以使NumCol
和NumberColumn
的行为类似,请参见我的编辑。另一种选择是在成对的(字符串,[Double])
上定义sumColumn
,但这也有它的缺点。这会起作用,但这是一个可读性问题。NumCol和NumberColumn是/代表同一事物,因此我非常希望有一个单一的名称。@PetrasPurlys那里可能没有免费的午餐。但是,您可以使NumCol
和NumberColumn
的行为类似,请参见我的编辑。另一个选项是对(字符串,[Double])
定义sumColumn
,但这也有它的缺点。如果我遗漏了一些东西,我很抱歉,但这怎么能让我保留不同列的列表呢?从这个问题上看,这不是一个明显的要求。@PetraSpurly不幸的是,这两个功能是不兼容的:要么类型系统区分这两个东西,因此,您可以编写一个只接受数字列的函数,或者类型系统不区分这两项,因此您可以将它们都放在列表中。如果您想要两种功能,您需要两种(集合)类型,一种是可分辨的,另一种是不可分辨的。@PetrasPurlys您可以将a
移到右侧,然后重新获得所需的电源<代码>数据列=全部a。ToColumn a=>Column a(但随后您将丢失并跟踪类型签名中的a
)如果我遗漏了什么,我很抱歉,但是这怎么能让我保留一个不同列的列表呢?从这个问题上看,这不是一个明显的要求。@PetrasPurlys不幸的是,这两个功能不兼容:要么类型系统区分这两个东西,所以你可以编写一个只接受数字列的函数,或者,类型系统无法区分这两件事,因此可以将它们都放在列表中。如果您想要两种功能,您需要两种(集合)类型,一种是可分辨的,另一种是不可分辨的。@PetrasPurlys您可以将a
移到右侧,然后重新获得所需的电源<代码>数据列=全部a。ToColumn a=>Column a(但随后您将丢失并跟踪类型签名中的a
)