在Haskell中按构造函数分组数据类型
给定此数据类型在Haskell中按构造函数分组数据类型,haskell,types,generic-programming,Haskell,Types,Generic Programming,给定此数据类型 data Val = X Int | Y Bool | Z Double deriving (Eq, Show) 和一个列表,例如 let vals = [X 1, Z 2.7, Y True, X 2, Z 3.14, Y True] 如何将VAL中的元素分组到此列表中 [[X 1,X 2],[Y True,Y True],[Z 2.7, Z 3.14]] 我有以下建议: data Val = X Int | Y Bool | Z Double deriving (Eq,
data Val = X Int | Y Bool | Z Double deriving (Eq, Show)
和一个列表,例如
let vals = [X 1, Z 2.7, Y True, X 2, Z 3.14, Y True]
如何将VAL
中的元素分组到此列表中
[[X 1,X 2],[Y True,Y True],[Z 2.7, Z 3.14]]
我有以下建议:
data Val = X Int | Y Bool | Z Double deriving (Eq, Ord, Show)
vals :: [Val]
vals = [X 1, Z 2.7, Y True, X 2, Z 3.14, Y True]
valCtorEq :: Val -> Val -> Bool
valCtorEq (X _) (X _) = True
valCtorEq (Y _) (Y _) = True
valCtorEq (Z _) (Z _) = True
valCtorEq _ _ = False
然后:
*Main Data.List> groupBy valCtorEq $ sort vals
[[X 1,X 2],[Y True,Y True],[Z 2.7,Z 3.14]]
要添加到@RamonSnir的答案中,还可以使用“废弃样板”框架自动构造用于按构造函数对数据类型进行分组的函数:
{-# LANGUAGE DeriveDataTypeable #-}
import Data.Data
import Data.Function (on)
import Data.List (groupBy, sort)
data Val = X Int | Y Bool | Z Double
deriving (Eq, Ord, Show, Typeable, Data)
vals :: [Val]
vals = [X 1, Z 2.7, Y True, X 2, Z 3.14, Y True]
main :: IO ()
main = print $ groupBy (on (==) toConstr) $ sort vals
这两个重要部分是:
- 导出可键入的
和,以及
- 用于获取特定值中使用的构造函数的表示形式
- 如果所考虑的类型不在
中(例如,因为其中某处有一个函数),该怎么办李>Ord
- 此外,此操作在列表长度中是否应该是O(n logn)
- 最后,提供的示例不足以确定分组是否应该是稳定的,也就是说:分组
的结果应该是[x2,x1]
(这是使用基于[x1,x2]
排序的解决方案时得到的结果),还是应该保持元素的原始顺序
groupByConstructor vals
给出了[[x2,x1],[ytrue,yfalse],[z2.7,z3.14,z0.2]
,我认为这是应该的
它不适用于对
Int
s、Char
s、Float
s或Ptr
和Array
等不可表示类型的列表进行排序。通过使用一种算法,使用可能的构造函数的数量进一步向下推线性常数,它可能会变得更有效,但是IntMap
现在必须做:-)不幸的是,这不是OP要求的。其目的是通过构造函数对值进行分组,而不是通过相等来分组。@PetrPudlák你说得很对,我使用了错误的文件,没有读取输出。。。我来编辑。
{-# LANGUAGE DeriveDataTypeable, StandaloneDeriving #-}
import Data.Data
import qualified Data.IntMap as IM
groupByConstructor :: Data a => [a] -> [[a]]
groupByConstructor = map ($ []) . IM.elems . IM.fromListWith (flip (.))
. map (\a -> (constrIndexOf a, (a:))) where constrIndexOf = constrIndex . toConstr
-- definition of Val as originally posed, without Ord:
data Val = X Int | Y Bool | Z Double deriving (Eq, Show)
deriving instance Typeable Val
deriving instance Data Val
-- new example:
vals = [X 2, Z 2.7, Y True, X 1, Z 3.14, Y False, Z 0.2]