我在haskell中很新鲜,我在Haskell中定义了一个函数:
febs :: (Integral a)=> a -> a
febs n
| n<=0 =0
| n==1 =1
| n==2 =1
| otherwise =febs(n-1)+febs(n-2)
但是,它运行得如此之慢,当我做“febs 30”时,它需要大约10秒, 我在C ++中使用相同的函数,运行速度非常快。
int febs(int n)
{
if(n == 1 || n ==2)
{
return 1;
}
return febs(n-1)+febs(n-2);
}
有没有办法提升我的haskell功能速度?
答案 0 :(得分:21)
这是一个奇怪的比较,原因如下:
您没有说您是在编译Haskell代码还是使用哪些选项。如果您只是在ghci中运行它,那么它当然会很慢 - 您将解释的代码与已编译的代码进行比较。
您的Haskell代码是多态的,而您的C ++代码是单态的(也就是说,您使用了类型类Integral a => a -> a
而不是具体类型Int -> Int
)。因此,您的Haskell代码比C ++代码更通用,因为它可以处理任意大的整数,而不是限制在Int
的范围内。编译器可能会对此进行优化,但我不确定。
如果我将以下代码放在文件fib.hs
中fibs :: Int -> Int
fibs n = if n < 3 then 1 else fibs (n-1) + fibs (n-2)
main = print (fibs 30)
并使用ghc -O2 fib.hs
进行编译,然后它运行得足够快,以至于它对我来说是即时的。你应该尝试一下,看看它与C ++代码的比较。
答案 1 :(得分:13)
尝试使用优化进行编译。使用GHC 7.4.1和-O2,您的程序运行得非常快:
$ time ./test
832040
real 0m0.057s
user 0m0.056s
sys 0m0.000s
这是main = print (febs 30)
。
关于Chris Taylor的答案中的多态性考虑,这里是febs 40
具有OP的多态Fibonacci函数:
$ time ./test
102334155
real 0m5.670s
user 0m5.652s
sys 0m0.004s
这是一个非多态的,即OP的签名替换为Int -> Int
:
$ time ./test
102334155
real 0m0.820s
user 0m0.816s
sys 0m0.000s
Per Tikhon Jelvis的评论,看看加速是由于用Integer
替换Int
,还是由于摆脱多态性,这很有趣。这是同一个程序,除了febs
根据Daniel Fischer的评论移动到新文件,并与febs :: Integer -> Integer
一起移动:
$ time ./test
102334155
real 0m5.648s
user 0m5.624s
sys 0m0.008s
同样,febs
位于不同的文件中,并且具有与原始相同的多态签名:
$ time ./test
102334155
real 0m16.610s
user 0m16.469s
sys 0m0.104s
答案 2 :(得分:3)
你也可以写这样的函数:
fibs = 0:1:zipWith (+) fibs (tail fibs)
它非常快,即使是大'n'立即执行:
Prelude> take 1000 fibs