我正在学习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]]
任何帮助将不胜感激。
答案 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 []
[[]]
我把它留作进一步改进的练习。