haskell - Haskell - 我如何编写一个惯用且有效的循环?
问题描述
我对 Haskell 比较陌生,所以我正在解决一些旧的代码出现问题以熟悉该语言。
但是,我在 2017 年第 17 天,第二部分卡住了。我已经尝试了三种解决方案来解决这个问题。
(编辑:将代码块简化为更清晰的示例)
以下解决方案是我希望能够适度有效地工作的东西:
run :: IO()
run = do
print "Starting:"
print (iteration''' 0 1 3 0 50000000)
iteration''' :: Int -> Int -> Int -> Int -> Int -> (Int, Int, Int, Int)
iteration''' cp cv ss zv 0 = (cp, cv, ss, zv)
iteration''' cp cv ss zv count = iteration''' ncp ncv ss nzv (count - 1)
where
ncp = ((cp + ss) `mod` cv) + 1
nzv = if ncp == 1 then cv else zv
ncv = cv + 1
问题是这三个都非常低效,无论是在内存方面还是在 CPU 方面。等效的 C 代码将类似于以下内容(非常快速地完成)。
int stepSize = 3;
int zv = 0;
int position = 0;
for (int i = 0; i < 50000000; i++) {
position = (position + stepSize) % i;
if (position == 0) zv = i;
}
我认为iteration'''
可以编译成类似的东西——但它会消耗千兆字节的内存并循环很长时间。
总结我的问题 - 在 Haskell 中“有效解决这个问题”的惯用方法是什么?当不需要实际的对象转换时,为什么它会占用这么多的堆空间?
我正在使用 ghc (cabal) 进行编译。
解决方案
为了完整起见,正如 Daniel Wagner 和 chi 所回答的:
所述代码中的问题是严格性(隐含大量惰性求值的整数会导致大量开销)。
这种方法要快很多(添加表BangPatterns
头)
iteration''' :: Int -> Int -> Int -> Int -> Int -> (Int, Int, Int, Int)
iteration''' !cp !cv !ss !zv 0 = (cp, cv, ss, zv)
iteration''' !cp !cv !ss !zv !count = iteration''' ncp ncv ss nzv (count - 1)
where
ncp = ((cp + ss) `mod` cv) + 1
nzv = if ncp == 1 then cv else zv
ncv = cv + 1
我认为这意味着这也是编写(一些)高性能代码的惯用方式!
推荐阅读
- php - 如何在 Opencart 中成功付款后立即触发发布到外部 Web api?
- swift - 编码/解码 UIBezierPath 到 CoreData 问题
- jenkins - org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException:找不到这样的字段:字段 java.lang.String
- unit-testing - 使用 CamelTestSupport 进行单元测试时,Camel 拆分器不会拆分消息
- python-3.x - 扩展空格的 Python 程序,并应根据输入文本/句子增加
- typescript - TypeScript:为一组导入的方法断言更正此上下文
- xml - 在 Informatica Cloud 中自动解析多个 XML 文件
- python - 将由通用分隔符分隔的 .txt 文件读入数据框
- django - heroku 未能处理 requirements.txt “因为这些软件包版本具有冲突的依赖关系。”
- python - 当列表推导返回所有内容时,为什么 for 循环只返回第一项?