[英]Haskell slow to compute Ackermann 4 1?
这是7个月前的一个老问题,当时堆栈溢出器同意Haskell计算Ackermann函数的低效率是由于编译器错误造成的。
7个月后,这似乎是固定的。 似乎ack使用线性内存运行,但它运行速度非常慢。
main = print (ack 4 1)
-- Ackermann function
ack 0 n = n + 1
ack m 0 = ack (m-1) 1
ack m n = ack (m-1) (ack m (n - 1))
$ time ./ack
65533
>real 8m53.274s
>user 8m47.313s
>sys 0m4.868s
Processor 2.8 GHz Intel Core i7
Memory 8 GB 1333 MHz DDR3
Software Mac OS X Lion 10.7.5 (11G63)
我只是要求对此有任何见解。 更详细的将得到投票。 请记住,我是函数式编程的新手,甚至关于尾递归与常规递归的简单评论也会受到赞赏和赞成。
我不知道你是怎么运行的,但我怀疑完整列表是:
看来你没有使用优化。 编译时一定要使用-O2
和try -fllvm
。 新时间: 1m2.412s
使用显式类型签名并Int
使用Int
(默认值为Integer
)。 新时间: 0m15.486s
因此,我们通过使用优化获得了近8倍的加速(为什么每个其他基准测试问题都没有使用优化标志?!?!?)和使用Int
而不是Integer
的额外约4倍。
为ack
添加类型签名:
ack :: Int -> Int -> Int
这应解决您的代码的两个问题:
如果没有签名,编译器将派生以下类型:
ack :: (Eq a, Eq b, Num a, Num b) => a -> b -> b
ack
最终推广到所有数字类型,而不仅仅是整数。 这个额外的间接层使代码变慢。
给ack
一个具体类型(比如Int
)会删除这个间接。
另外,我猜你的主要动作是这样写的:
main = print (ack 4 1)
您的ack
适用于任何数字类型,但您没有准确指定哪一个。 这意味着GHC在一个称为类型默认的过程中自动选择一个。
在这种情况下,它选择Integer
,一种可变长度类型。 因为Integer
可以处理任意大小的数字,所以它比机器大小的Int
慢得多。
总结一下:
-Wall
编译。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.