我是Haskell的新手,我正在尝试编写一个(某种程度上)基本的递归函数来生成集合的分区。我正在引用这个wiki页面(https://en.wikipedia.org/wiki/Partition_of_a_set)来定义set partition。
我目前有一个产生大部分但不是全部分区的功能:
#O_nas {
background: transparent url('images/o_nas.png') center center no-repeat;
}
#O_nas:hover {
box-shadow: 0px 0px 1px #fff;
}
正如您所看到的,它缺少separate :: [a] -> [[[a]]]
separate [] = [[]]
separate (b:bs) = [[b]:s | s <- separate bs] ++ [(b:qs):qss | (qs:qss) <- separate bs]
>separate [1,2,3]
[[[1],[2],[3]],[[1],[2,3]],[[1,2],[3]],[[1,2,3]]]
变体。
我想知道是否可以轻松修改此功能以满足我的要求,或者是否需要创建一个全新的功能。感谢。
答案 0 :(得分:3)
问题在于,使用[(b:qs):qss | (qs:qss) <- separate bs]
,您只会将b
添加到每个bs
分区的第一个子集中。您希望将其添加到每个子集。
separate (b:bs) = [[b]:s | s <- separate bs]
++ (singleModifies (b:) =<< separate bs)
-- | All possibilities of applying a function to exactly one element in the list.
singleModifies :: (a->a) -> [a] -> [[a]]
singleModifies _ [] = []
singleModifies f (x:xs) = (f x:xs) : map (x:) (singleModifies f xs)
如果您不了解=<<
运算符的作用:它会“扁平化”列表的嵌套。 separate bs
已生成分区列表;对于其中的每一个,我们都会从singleModifies
获得另一个列表,但最后我们对哪个列表来自哪里不感兴趣,所以我们只是join(又名concat)他们一起。写这个的另一种方式是
separate (b:bs) = [[b]:s | s <- separate bs]
++ concat [singleModifies (b:) bp | bp <- separate bs]