列表分区以递归方式实现

时间:2016-02-14 05:38:40

标签: haskell

我是Haskell初学者,我一直在尝试递归函数。

我正在研究一个函数:

 separate :: [a] -> [[[a]]]

接收列表并输出该列表的所有分区。

例如,123变为:

1|2|3
12|3
1|23
13|2
132

我只能实现一个创建1|2|3变体的递归函数:

separate' :: [a] -> [[a]]
separate' (r:rs) = [r]:separate' xs

>separate [1,2,3]
[[1],[2],[3]]

我一直试图用递归创建其他变种。

2 个答案:

答案 0 :(得分:3)

您可以将此功能视为选择两个列表元素之间的每个位置,是否在那里包含拆分。因此对于初学者来说,n元素列表应该有2个 n-1 分区:您可以将其用作对可能解决方案的快速健全性检查。

建模非确定性的一个好方法是使用列表monad(或者等同于列表推导),所以让我们这样做。

首先,让我们写出类型和基本情况:

separate :: [a] -> [[[a]]]
separate [] = [[]]

有一种方法可以分隔一个空列表:空列表本身,不存在拆分的可能性。很容易。

现在,鉴于我们有一个元素和剩余元素列表,我们需要确定的一件事是列出所有分割其余元素的方法:

separate :: [a] -> [[[a]]]
separate [] = [[]]
separate (x:xs) = let recur = separate xs
                  in undefined -- TODO

这是有趣的东西开始的地方。正如我所说,您可以将此视为选择每个项目是否在其后进行拆分。两个选择意味着将两个列表连接在一起,所以让我们这样做:

separate :: [a] -> [[[a]]]
separate [] = [[]]
separate (x:xs) = let recur = separate xs
                      split = undefined -- TODO
                      noSplit = undefined -- TODO
                  in split ++ noSplit

现在,我们如何在项目x之后引入拆分?我们为recur中的每个分区执行此操作,将[x]添加到其前面作为新分区:

separate :: [a] -> [[[a]]]
separate [] = [[]]
separate (x:xs) = let recur = separate xs
                      split = do
                        partition <- recur
                        return $ [x] : partition
                      noSplit = undefined -- TODO
                  in split ++ noSplit

不分裂怎么办?非常相似!对于recur中的每个分区,我们将x添加到第一个子分区的前面:

separate :: [a] -> [[[a]]]
separate [] = [[]]
separate (x:xs) = let recur = separate xs
                      split = do
                        partition <- recur
                        return $ [x] : partition
                      noSplit = do
                        (y:ys) <- recur
                        return $ (x:y):ys
                  in split ++ noSplit

有了这个,我们就完成了:

*Temp> separate "123"
[["1","2","3"],["1","23"],["12","3"],["123"]]

答案 1 :(得分:0)

正确的折叠解决方案是:

import Control.Applicative ((<$>))

separate :: Foldable t => t a -> [[[a]]]
separate = foldr (\i -> concatMap (inc i)) [[]]
    where
    inc i []     = [[[i]]]
    inc i (x:xs) = ((i:x):xs):((x:) <$> inc i xs)

然后:

\> separate [1, 2]
[[[1,2]],[[2],[1]]]

\> separate [1, 2, 3]
[[[1,2,3]],[[2,3],[1]],[[1,3],[2]],[[3],[1,2]],[[3],[2],[1]]]