组总和为N:使用列表清单

时间:2019-09-08 22:34:58

标签: haskell

我正在学习Haskell,正在研究一个将数字n和列表iL相加的问题。使用这些,您可以检查哪些连续数字将小于n,并将其存储在列表中。您可以有多个列表。我创建了一个名为groupSumtoN的函数,该函数将返回此列表列表。

我创建了一个辅助函数helperToSum,以递归方式创建列表并返回输出,该输出采用数字n,input和acc(结果)。

这是我到目前为止尝试过的:

groupSumtoN :: (Ord a, Num a) => a -> [a] -> [[a]]
groupSumtoN n [] = []
groupSumtoN n iL = (helperToSum n iL [])

helperToSum n [] acc = acc
helperToSum n (x:xs) acc | (sum acc) + x < n = (helperToSum n xs (acc : x))
                         | (sum acc) + x > n = acc:(helperToSum n xs [x])

我遇到两个无限类型错误,一个错误是从groupSumtoN调用helperToSum,另一错误是在此行。

(sum acc) + x < n = (helperToSum n xs (acc : x))

作为一个例子,我有一个下面该函数如何工作的示例:

groupSumtoN 15 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[[1,2,3,4,5],[6,7],[8],[9],[10]]

任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:2)

基本情况:

helperToSum n [] acc = acc

没有太大意义,因为它需要一个列表列表。您需要返回一个单例列表:

helperToSun n [] acc = [acc]

另一个问题是(acc : x)无效。 (:)是列表的构造函数,类型为(:) :: a -> [a] -> [a]。您不能使用它附加值。现在,我们可以使用(x : acc)。在这种情况下,您以后需要撤消操作。

最好使用otherwise作为第二后卫。例如,在这里有可能总和恰好是n,而这种情况目前尚未涵盖。

考虑到这些问题,我们可以使用以下功能修复编译错误:

helperToSum :: (Ord a, Num a) => a -> [a] -> [a] -> [[a]]
helperToSum n [] acc = [acc]
helperToSum n (x:xs) acc | (sum acc) + x <= n = (helperToSum n xs (x : acc))
                         | otherwise = acc:(helperToSum n xs [x])

但是,这里的组将相反,而且效率不是很高。我们可以做一个更懒惰的变体,即时计算一组中剩余的空间,并根据该条件分配当前组或下一组中的项目:

groupSumtoN :: (Ord a, Num a) => a -> [a] -> [[a]]
groupSumtoN n = go n
    where go _ [] = [[]]
          go r (x:xs) | x <= r = let (t:tl) = go (r-x) xs in (x:t) : tl
                      | x > n = error "Item too large"
                      | otherwise = [] : go n (x:xs)

这里有一个空列表,将产生一个单独的组:

Prelude> groupSumtoN 15 []
[[]]

我把它留作进一步改进的练习。