Haskell极慢的简单复发
我正在尝试haskell
用简单的递归max
算法进行分析:
max_tag :: Integer -> [Integer] -> Integer
max_tag head [] = head
max_tag head (x:xs) =
let {m = max_tag x xs} in
let {b = (Prelude.<=) m head} in
case b of {True -> head; False -> m}
当我将其与python势在必式等价物进行比较时,我会得到 10x速度因子赞成Python:
with open("input.txt") as fl:
data = [int(d) for d in fl.read().splitlines()]
max_ = 0
for d in data:
if max_ < d:
max_ = d
print(max_)
- 似乎在
haskell
案例中使用 tail recursion 的固有限制,我对吗? - 有什么其他使Haskell代码更快的方法?
- 输入文件包含
1M
未签名的,无绑定的整数(平均32位数字)
,这是完整的haskell
file(不确定需要它):
import Max
import System.IO
import Control.Monad
import System.Environment
import Prelude
readInt :: String -> Integer
readInt = read
max_tag :: Integer -> [Integer] -> Integer
max_tag head [] = head
max_tag head (x:xs) =
let {m = max_tag x xs} in
let {b = (Prelude.<=) m head} in
case b of {True -> head; False -> m}
main = do
args <- getArgs
contents <- readFile "input.txt"
let numbers_as_strings = words $ contents
let numbers = map readInt numbers_as_strings
let max_number = max_tag 0 numbers
print max_number
编辑: @willem van onsem建议的重构, 作品! (28秒 - &gt; 12秒)
max_bar :: Integer -> [Integer] -> Integer
max_bar head [] = head
max_bar head (x:xs) =
let {b = head < x} in
let {m = case b of {True -> x; False -> head}} in
max_bar m xs
关于进一步改进的任何想法?我必须比Python快!
I'm experimenting with Haskell
profiling with a simple recursive max
algorithm:
max_tag :: Integer -> [Integer] -> Integer
max_tag head [] = head
max_tag head (x:xs) =
let {m = max_tag x xs} in
let {b = (Prelude.<=) m head} in
case b of {True -> head; False -> m}
When I compare it to a python imperative equivalent, I get a 10x speed factor in favor of python:
with open("input.txt") as fl:
data = [int(d) for d in fl.read().splitlines()]
max_ = 0
for d in data:
if max_ < d:
max_ = d
print(max_)
- It seems there is an inherent limitation of using tail recursion in the
Haskell
case, am I right? - Any other way to make the Haskell code faster?
- The input file contains
1M
unsigned, unbounded integers (on average 32 digits)
For completeness, here is the complete Haskell
file (not sure it is needed):
import Max
import System.IO
import Control.Monad
import System.Environment
import Prelude
readInt :: String -> Integer
readInt = read
max_tag :: Integer -> [Integer] -> Integer
max_tag head [] = head
max_tag head (x:xs) =
let {m = max_tag x xs} in
let {b = (Prelude.<=) m head} in
case b of {True -> head; False -> m}
main = do
args <- getArgs
contents <- readFile "input.txt"
let numbers_as_strings = words $ contents
let numbers = map readInt numbers_as_strings
let max_number = max_tag 0 numbers
print max_number
EDIT:
refactor suggested by @Willem Van Onsem,
works ! (28 sec -> 12 sec)
max_bar :: Integer -> [Integer] -> Integer
max_bar head [] = head
max_bar head (x:xs) =
let {b = head < x} in
let {m = case b of {True -> x; False -> head}} in
max_bar m xs
Any ideas on further improvements? I must be faster than python !
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
一种比 @noughtmare的答案更有效的方法是使用
data.bytestring
,它没有处理编码的开销,这里不需要。在我的测试中,以100万个随机32位数字作为输入,这在〜290ms中运行,而 @noughtmare的答案在约1020毫秒内运行。为了进行比较,原始的Python One运行〜560ms。An even more efficient way than @Noughtmare's answer is to use
Data.ByteString
which does not have the overhead of handling encodings, which is not needed here. In my tests, with one million random 32 digit numbers as input, this runs in ~290ms while the answer by @Noughtmare runs in ~1020ms. For comparison, the original Python one runs in ~560ms.使用此功能基于您的函数应该使其变得更快(也请确保使用
文本
版本2.0或更高版本):您还可以通过制作来加快
max_tag
函数来加快速度它会递归递归,从而避免了大量内存分配:您可以使用
foldr
使其更快地使其更快,以便使用MAP READINT
获得foldr/build Fusion:Using this to benchmark your function should make it go much faster (also be sure to use
text
version 2.0 or later):You can also speed up your
max_tag
function itself by making it tail recursive and thus avoiding a bunch of memory allocations:You can make it even slightly faster by using
foldr
so that you get foldr/build fusion withmap readInt
: