Haskell 脚本空间不足
我正在使用 Euler 项目自学 Haskell,但我在推理 Haskell 如何执行我的代码时遇到了一些麻烦。 第二个问题让我计算 400 万以内所有偶数斐波那契数的总和。 我的脚本如下所示:
fibs :: [Integer]
fibs = 1 : 2 : [ a+b | (a,b) <- zip fibs (tail fibs)]
evens :: Integer -> Integer -> Integer
evens x sum | (even x) = x + sum
| otherwise = sum
main = do
print (foldr evens 0 (take 4000000 fibs))
Hugs 给出错误“垃圾收集无法回收足够的空间”,我认为这意味着列表条目在被 foldr
消耗时不会被释放。
我需要做什么来解决这个问题? 我尝试编写一个使用累加器的尾递归(我认为)版本,但也无法使其工作。
I'm using project Euler to teach myself Haskell, and I'm having some trouble reasoning about how my code is being executed by haskell. The second problem has me computing the sum of all even Fibonacci numbers up to 4 million. My script looks like this:
fibs :: [Integer]
fibs = 1 : 2 : [ a+b | (a,b) <- zip fibs (tail fibs)]
evens :: Integer -> Integer -> Integer
evens x sum | (even x) = x + sum
| otherwise = sum
main = do
print (foldr evens 0 (take 4000000 fibs))
Hugs gives the error "Garbage collection fails to reclaim sufficient space", which I assume means that the list entries are not released as they are consumed by foldr
.
What do I need to do to fix this? I tried writing a tail-recursive (I think) version that used accumulators, but couldn't get that to work either.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
首先,你不应该拥抱。 它只是一个仅用于教学目的的玩具。
然而,GHC 是 Haskell 的快速、多核就绪优化编译器。 在此处获取。 特别是,它进行严格性分析,并编译为本机代码。
您的代码中最突出的一点是在一个非常大的列表上使用foldr。 也许您想要一个尾递归循环。 像这样:
除此之外,前 4M 偶数 fib 将使用相当多的空间,因此需要一段时间。
这是前 400k 个偶数 fib 的总和,以节省您一些时间(21 秒)。 :-)
Firstly, you shouldn't use hugs. It is a toy for teaching purposes only.
GHC, however, is a fast, multicore-ready optimizing compiler for Haskell. Get it here. In particular, it does strictness analysis, and compiles to native code.
The main thing that stands out about your code is the use of foldr on a very large list. Probably you want a tail recursive loop. Like so:
Besides all this, the first 4M even fibs will use a fair amount of space, so it'll take a while.
Here's the sum of the first 400k even fibs, to save you some time (21s). :-)
一些观察/提示:
x + sum
直到最后才被计算操作编辑以回复评论,
我不会告诉您更简单的方法是什么,因为这就是欧拉项目问题的乐趣所在。 但我会问你一堆问题:
A number of observations / hints:
x + sum
s from even aren't getting evaluated until the very endEdit in response to comment
I'm not going to tell you what the easier way is, since that's the fun of Project Euler problems. But I will ask you a bunch of questions:
你对问题的理解是错误的。 实际问题希望您将所有偶数斐波那契数相加,使得斐波那契数本身不超过 400 万(恰好是前 33 个斐波那契数)。
You understood the problem wrong. The actual problem wants you to sum all the even Fibonacci numbers such that the Fibonacci number itself doesn't exceed 4 million (which happens to be only the first 33 Fibonacci numbers).
您正在评估 400 万个
fibs
元素。 这些数字呈指数级增长。 我不知道需要多少字节来表示第一百万个斐波那契数; 仅千分之一的斐波那契数就有 211 个十进制数字,因此仅需要 22 个 32 位字来保存这些数字,更不用说gmp
带来的任何开销。 而且这些都呈指数级增长。练习:计算保存 400 万个斐波那契数所需的内存量。
You are evaluating four million elements of
fibs
. Those numbers grow exponentially. I don't know how many bytes are required to represent the millionth Fibonacci number; just the one-thousandth Fibonacci number has 211 decimal digits, so that's going to take 22 32-bit words just to hold the digits, never mind whatever overheadgmp
imposes. And these grow exponentially.Exercise: calculuate the amount of memory needed to hold four million Fibonacci numbers.
看一下 Prelude 函数 takeWhile、filter、even 和 sum
takeWhile (<40) [0..]
过滤偶数 $ takeWhile (<40) [0..]
将它们放在一起:
ans = sum $ 过滤偶数 $ takeWhile (< 4* 10^6) fibs
have a look at the Prelude functions takeWhile, filter, even, and sum
takeWhile (<40) [0..]
filter even $ takeWhile (<40) [0..]
put 'em together:
ans = sum $ filter even $ takeWhile (< 4* 10^6) fibs