问题
I am just beginner in Haskell. And I writing a code to display the N numbers in the Fibonacci sequence. Here is my code in Haskell,
fib_seq 1 = 1:[]
fib_seq 2 = 1:1:[]
fib_seq n = sum(take 2 (fib_seq (n-1))):fib_seq (n-1)
When I run this code for higher numbers like fib_seq 40
in GHCI, it takes a long time to evaluate it and my computer hangs and I have to interrupt. However, when I write the same exact logic in C, (I just print instead of saving it in the list),
#include<stdio.h>
int fib_seq (int n){
if(n==1) return 1;
else if(n==2) return 1;
else return fib_seq(n-1)+fib_seq(n-2); }
void print_fib(int n){
if(n==0) return;
else printf("%i ", fib_seq(n));
print_fib(n-1); }
int main(int argn, char* argc){
print_fib(40);
return 0; }
The code is very fast. Takes about 1 second to run when compiled with GCC. Is Haskell supposed to be this slow than C? I have looked up other answers on the internet and they say something about memoization. I am beginning Haskell and I don't know what that means. What I am saying is that the C code and Haskell code I wrote both do the same exact steps and Haskell is so much slower than C, it hangs my GHCI. A 1-2 seconds difference is something I will never worry about, and if C also had taken the same exact time as Haskell, I would also not worry about. But Haskell crashing and C doing it in 1 seconds is unacceptable.
回答1:
The following program, compiled with ghc -O2 test.hs
, is +/-2% the speed of the C code you posted, compiled with gcc -O2 test.c
.
fib_seq :: Int -> Int
fib_seq 1 = 1
fib_seq 2 = 1
fib_seq n = fib_seq (n-1) + fib_seq (n-2)
main = mapM_ (print . fib_seq) [40,39..1]
Some comments:
- Unlike you, I implemented the exact same logic. I doubt this is the real difference, though; see the remaining comments for much more likely causes.
- I specified the same types as C uses for the arithmetic. You didn't, which is likely to run into two problems: using
Integer
instead ofInt
for largenum arithmetic, and having a class-polymorphic type instead of a monomorphic one adding overhead on every function call. - I compiled. ghci is built to be interactive as quickly as possible, not to produce quick code.
- I don't have the right version of llvm installed at the moment, but it will often crunch through heavily-numeric code like this much better than ghc's own codegen. I wouldn't be too surprised if it ended up being faster than gcc.
Of course using one of the many well-known better algorithms for fibonacci is going to trump all this nonsense.
回答2:
Guess what happens if "fib_seq (n-1)" is evaluated twice on each recursion. And then try this:
fib_seq 1 = 1:[]
fib_seq 2 = 1:1:[]
fib_seq n = sum(take 2 f):f
where f = fib_seq (n-1)
来源:https://stackoverflow.com/questions/42771348/why-is-haskell-so-slow-compared-to-c-for-fibonacci-sequence