Haskell 清单的清单

Haskell 清单的清单,haskell,Haskell,作为列表列表,用什么方法来表示类型lola 属于属于a?嵌套级别是任意的,但总体上是一致的 外部列表的元素 我所考虑的情况是对 列表,然后对每个子组应用下一个分组,依此类推。信息技术 事先不知道需要申请多少组。因此: rGroupBy :: [(a -> a -> Bool)] -> [a] -> [...[a]...] rGroupBy;-)类型签名的额外布朗尼点数 例如: 假设deweygroupi根据第i个数字对元素进行分组 rGroupBy [deweyGrou

作为列表列表,用什么方法来表示类型
lola
属于属于
a
?嵌套级别是任意的,但总体上是一致的 外部列表的元素

我所考虑的情况是对 列表,然后对每个子组应用下一个分组,依此类推。信息技术 事先不知道需要申请多少组。因此:

rGroupBy :: [(a -> a -> Bool)] -> [a] -> [...[a]...]
rGroupBy
;-)类型签名的额外布朗尼点数

例如:

假设
deweygroupi
根据第i个数字对元素进行分组

rGroupBy [deweyGroup 1, deweyGroup 2] 
         ["1.1", "1.2.1", "1.2.2", "2.1", "2.2", "3"]
给出:

[ [ [ "1.1" ], [ "1.2.1", "1.2.2" ] ],
  [ [ "2.1" ], [ "2.2" ] ],
  [ [ "3" ] ]
]
Postscript


一天后,我们有4个优秀的互补解决方案。我对答案非常满意;谢谢大家。

你们实际上拥有的是一棵树。尝试用递归数据结构表示它:

data LoL a = SoL [a] | MoL [LoL a] deriving (Eq, Show)

rGroupBy :: [(a -> a -> Bool)] -> [a] -> LoL a
rGroupBy (f:fs) = MoL . map (rGroupBy fs) . groupBy f
rGroupBy []     = SoL

deweyGroup :: Int -> String -> String -> Bool
deweyGroup i a b = a!!idx == b!!idx where idx = 2*(i-1)
rGroupBy[deweyGroup 1,deweyGroup 2][“1.1”,“1.2.1”,“1.2.2”,“2.1”,“2.2”,“3.0”]
给出:

MoL [MoL [SoL ["1.1"],
          SoL ["1.2.1","1.2.2"]],
     MoL [SoL ["2.1"],
          SoL ["2.2"]],
     MoL [SoL ["3.0"]]
    ]

我相信下面的例子应该接近你的想法。首先,我们声明类型级别的自然数。然后我们定义向量,向量的长度为幻影类型(请参阅)。然后我们定义了一个嵌套列表的结构。。。它以幻影类型携带深度。最后,我们可以定义正确键入的
rGroupBy

{-#语言GADTs}
{-#语言空数据集}
导入数据列表(groupBy)
数据零点
数据成功
数据向量n a在哪里
零:向量零a
缺点:a->Vec n a->Vec(成功)a
数据在哪里
单例::a->LList Zero a
成功列表::[LIST n a]->LIST(成功)a
--不是很有效,但对于这个例子来说已经足够了。
实例Show a=>Show(LList n a)其中
showsPrec(单例x)=显示x
showsPrec(成功列表lls)=显示lls
rGroupBy::Vec n(a->a->Bool)->[a]->LList(suck n)a
rGroupBy Nil
=成功列表。映射单态
rGroupBy(Cons f fs)
=成功列表。映射(rgroupbyfs)。群比f
--试验------------------------------------------------------------
main=do
让输入=[“1.1”、“1.2.1”、“1.2.2”、“2.1”、“2.2”、“3”]
--不要分开任何东西
打印$rGroupBy Nil输入
--分成两层
打印$rGroupBy(Cons(deweyGroup 1)
(反对党(杜威集团2)无)
输入
哪里
deweyGroup::Int->String->String->Bool
杜威i组a=a!!idx==b!!idx,其中idx=2*(i-1)

如果您想要强制执行统一的深度,有一个(相当)标准的技巧涉及多态递归。我们要做的是有一系列“更深层”的构造函数来告诉列表嵌套的深度,然后是一个最终的“here”构造函数,其中包含深度嵌套的列表:

data GroupList a = Deeper (GroupList [a]) | Here a deriving (Eq, Ord, Show, Read)
实际上,定义的类型有一个美学选择,您可能希望在代码中有所不同:这里的
构造函数采用单个
a
,而不是
a
的列表。这个选择的结果在这个答案的其余部分是分散的

这是一个显示列表列表的此类值的示例;它有两个
更深的
构造函数,对应于它的深度二嵌套:

> :t Deeper (Deeper (Here [[1,2,3], []]))
Num a => GroupList a
下面是一些示例函数

instance Functor GroupList where
    fmap f (Here   a ) = Here   (f a)
    fmap f (Deeper as) = Deeper (fmap (fmap f) as)
    -- the inner fmap is at []-type

-- this type signature is not optional
flatten :: GroupList [a] -> GroupList a
flatten (Here   a ) = Deeper (Here a)
flatten (Deeper as) = Deeper (flatten as)

singleGrouping :: (a -> a -> Bool) -> GroupList [a] -> GroupList [a]
singleGrouping f = flatten . fmap (groupBy f)

rGroupBy :: [a -> a -> Bool] -> [a] -> GroupList [a]
rGroupBy fs xs = foldr singleGrouping (Here xs) fs

强制所有分支具有相同深度的约束的另一种方法是使用嵌套数据类型:

data LoL a = One [a] | Many (LoL [a])

mapLoL :: ([a] -> [b]) -> LoL a -> LoL b
mapLoL f (One xs) = One (f xs)
mapLoL f (Many l) = Many $ mapLoL (map f) l

rGroupBy :: [a -> a -> Bool] -> [a] -> LoL a
rGroupBy [] xs = One xs
rGroupBy (f:fs) xs = Many $ mapLoL (groupBy f) $ rGroupBy fs xs
扩展
LoL
的定义,我们非正式地看到

LoL a = [a] | [[a]] | [[[a]]] | ...
然后我们可以说,例如:

ghci> rGroupBy [(==) `on` fst, (==) `on` (fst . snd)] [ (i,(j,k)) | i<-[1..3], j<-[1..3], k<-[1..3]]

作为一种类型的黑客练习,可以使用标准列表来实现这一点

我们只需要一个任意深度的groupStringsBy函数:

{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts,
  UndecidableInstances, IncoherentInstances,
  TypeFamilies, ScopedTypeVariables #-}

import Data.List
import Data.Function

class StringGroupable a b where
    groupStringBy :: Pred -> a -> b

instance (StringGroupable a b, r ~ [b]) => StringGroupable [a] r where
    groupStringBy f = map (groupStringBy f)

instance (r ~ [[String]]) => StringGroupable [String] r where
    groupStringBy p = groupBy p
其工作原理如下:

*Main> let lst = ["11","11","22","1","2"]
*Main> groupStringBy ((==) `on` length) lst
[["11","11","22"],["1","2"]]
*Main> groupStringBy (==) . groupStringBy ((==) `on` length) $ lst
[[["11","11"],["22"]],[["1"],["2"]]]
*Main> app not not not True
False
*Main> app (+3) (*2) 2
10
因此,我们可以直接使用此函数(尽管它必须按相反顺序排列):

但是如果你想使用你的原始样品,我们也可以破解它。 首先,我们需要一个变量参数函数,该函数通过
将所有参数(最后一个除外)按相反顺序传输,然后将结果函数应用于最后一个参数:

class App a b c r where
    app :: (a -> b) -> c -> r

instance (b ~ c, App a d n r1, r ~ (n -> r1)) => App a b (c -> d) r where
    app c f = \n -> app (f . c) n

instance (a ~ c, r ~ b) => App a b c r where
    app c a = c a
工作原理如下:

*Main> let lst = ["11","11","22","1","2"]
*Main> groupStringBy ((==) `on` length) lst
[["11","11","22"],["1","2"]]
*Main> groupStringBy (==) . groupStringBy ((==) `on` length) $ lst
[[["11","11"],["22"]],[["1"],["2"]]]
*Main> app not not not True
False
*Main> app (+3) (*2) 2
10
然后使用谓词类型的自定义规则将其展开
type Pred=String->String->Bool

type Pred = String -> String -> Bool

instance (StringGroupable b c, App a c n r1, r ~ (n -> r1)) => App a b Pred r where
    app c p = app ((groupStringBy p :: b -> c) . c)
最后将其包装到
rGroupBy
(提供
id
函数作为管道中的第一个函数):

现在,它应该适用于任何数量的
Pred
类型的分组谓词,生成与所提供谓词数量相等的深度列表:

-- gives: [["1.1","1.2.1","1.2.2"],["2.1","2.2"],["3"]]
test2 = rGroupBy (deweyGroup 1) inp

-- gives: [[["1.1"],["1.2.1","1.2.2"]],[["2.1"],["2.2"]],[["3"]]]
test3 = rGroupBy (deweyGroup 1) (deweyGroup 2) inp

-- gives: [[[["1.1"]],[["1.2.1","1.2.2"]]],[[["2.1"]],[["2.2"]]],[[["3"]]]]
test4 = rGroupBy (deweyGroup 1) (deweyGroup 2) (deweyGroup 1) inp

因此,这是可能的(并且可能可以简化),但与往常一样,除了练习之外,不建议将这种黑客技术用于任何事情。

有趣的问题。当你说“它不是预先知道的”时,你的意思是在编译时?在C/C++中,一个列表通常是一个数组,一个数组通常是一个二维矩阵,制作一个数组列表意味着你将维度增加1,从2增加到3,数组列表是一个三维矩阵(从抽象的角度看);我不知道Haskell,但您的问题可能只是关于矩阵/向量维度。@user827992,在Haskell中,列表是列表,而不是数组。(准确地说,这是一个单链表)@dflemstr我刚才只是举了一个例子,说明如何在C/C++中实现这一点,我认为解决方案可能在于多维方法。@jberryman:我的意思是在编译时。私下里,我希望哈斯凯尔的巫师能从他的盖德帽子里变出一些漂亮的类型,既解决了我的问题,又提供了一个学习的榜样。我认为这在GADT中是可能的(因为这似乎允许类型系统强制执行具有固定长度的向量),但我发现它们目前不在我的掌握范围之内。我自己也说得再好不过了。另外,看看玫瑰树。非常好的解决方案。我看到的唯一问题是树结构不强制均匀深度。@Petr有可能修改为强制均匀深度吗?确实很好。我错过了我想说的那一点
-- gives: [["1.1","1.2.1","1.2.2"],["2.1","2.2"],["3"]]
test2 = rGroupBy (deweyGroup 1) inp

-- gives: [[["1.1"],["1.2.1","1.2.2"]],[["2.1"],["2.2"]],[["3"]]]
test3 = rGroupBy (deweyGroup 1) (deweyGroup 2) inp

-- gives: [[[["1.1"]],[["1.2.1","1.2.2"]]],[[["2.1"]],[["2.2"]]],[[["3"]]]]
test4 = rGroupBy (deweyGroup 1) (deweyGroup 2) (deweyGroup 1) inp