Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Haskell中按构造函数分组数据类型_Haskell_Types_Generic Programming - Fatal编程技术网

在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
这两个重要部分是:

  • 导出可键入的
    和,以及
  • 用于获取特定值中使用的构造函数的表示形式
(这可能是过分的,但这是一个很有意思的问题!)

提供的答案有3个小问题:

  • 如果所考虑的类型不在
    Ord
    中(例如,因为其中某处有一个函数),该怎么办
  • 此外,此操作在列表长度中是否应该是O(n logn)
  • 最后,提供的示例不足以确定分组是否应该是稳定的,也就是说:分组
    [x2,x1]
    的结果应该是
    [x1,x2]
    (这是使用基于
    排序的解决方案时得到的结果),还是应该保持元素的原始顺序
这是我能想到的最普遍的解决方案。它是稳定的,不需要Ord(事实上你甚至不需要接触原始数据类型),并且它在大约O(n*min(n,W))的时间内运行,其中W是你机器的字大小(在我的机器上,它是64)。也就是说,一旦列表长度超过64个ish元素,它就是线性的(我说“大约”,因为分组的元素仍然需要从差异列表中重新组合)

现在
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]