在Haskell中拆分列表

时间:2018-02-11 14:36:38

标签: haskell functional-programming

在Haskell中,我需要执行一个函数,其类型声明如下:

split ::[Integer] -> Maybe ([Integer],[Integer])

让它如下工作:

split [1,2,3,4,5,15] = Just ([1,2,3,4,5],[15])

因为,1 + 2 + 3 + 4 + 5 = 15

split [1,3,3,4,3] = Just ([1,3,3],[4,3])

因为,1 + 3 + 3 = 7 = 4 + 3

split [1,5,7,8,0] = Nothing

我试过这个,但它不起作用:

split :: [Integer] -> ([Integer], [Integer])
split xs = (ys, zs)
 where
   ys <- subsequences xs,  ys isInfixOf xs, sum ys == sum zs
   zs == xs \\ ys

确定正整数列表xs是否可以用相同的和分成两部分(不重新排列其元素)。如果可能,其值是由两部分组成的对。如果不是,则其值为Nothing。 我该怎么办?

2 个答案:

答案 0 :(得分:3)

不是一个完整的答案,因为这是一个学习练习并且您需要提示,但如果您想使用subsequences中的Data.List,则可以删除您正在检查的子序列的每个元素带有\\的原始列表,以获得差异,并比较总和。你是在正确的轨道上,但你需要找到有效的第一个子序列并返回Just (ys, zs),否则Nothing

您可以将某个给定子序列的测试作为谓词,并使用find进行搜索。

答案 1 :(得分:1)

您还可以创建一个函数,该函数提供列表的所有可能拆分:

splits :: [a] -> [([a], [a])]
splits xs = zipWith splitAt [1..(length xs)-1] $ repeat xs

其工作原理如下:

*Main> splits [1,2,3,4,5,15]
[([1],[2,3,4,5,15]),([1,2],[3,4,5,15]),([1,2,3],[4,5,15]),([1,2,3,4],[5,15]),([1,2,3,4,5],[15])]

然后您可以使用Data.List中的find来查找具有相等总和的第一对拆分列表:

import Data.List

splitSum :: [Integer] -> Maybe ([Integer], [Integer])
splitSum xs = find (\(x, y) -> sum x == sum y) $ splits xs

符合预期:

*Main> splitSum [1,2,3,4,5,15]
Just ([1,2,3,4,5],[15])

由于find返回Maybe a,因此类型会自动匹配。