首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Haskell显式递归vs“`iterate`”

Haskell显式递归vs“`iterate`”
EN

Stack Overflow用户
提问于 2018-07-19 20:39:19
回答 1查看 468关注 0票数 15

在Haskell中使用iterate编写函数时,我发现具有显式递归的等效版本似乎要快得多--尽管我认为在Haskell中应该反对显式递归。

类似地,我期望GHC能够适当地内联/优化列表组合器,以便得到的机器代码至少与显式递归类似。

这里有一个(不同的)例子,它也显示了我观察到的减速。

steps m n及其变体steps'计算n达到1的Collatz步骤数,在m尝试后放弃。

steps使用显式递归,而steps'使用列表函数。

代码语言:javascript
复制
import Data.List (elemIndex)
import Control.Exception (evaluate)
import Control.DeepSeq (rnf)

collatz :: Int -> Int
collatz n
  | even n    = n `quot` 2
  | otherwise = 3 * n + 1

steps :: Int -> Int -> Maybe Int
steps m = go 0
  where go k n
          | n == 1    = Just k
          | k == m    = Nothing
          | otherwise = go (k+1) (collatz n)

steps' :: Int -> Int -> Maybe Int
steps' m = elemIndex 1 . take m . iterate collatz

main :: IO ()
main = evaluate $ rnf $ map (steps 800) $ [1..10^7]

我通过评估到10^7的所有值来测试这些值,每个值都在800步骤之后放弃。在我的机器上(用ghc -O2编译),显式递归只需不到4秒(3.899s),而列表组合子则花费了大约5倍的时间(19.922s)。

为什么在这种情况下显式递归要好得多?在保持性能的同时,是否有一种在不显式递归的情况下编写它的方法?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-07-20 19:24:03

更新:我为这个bug提交了Trac 15426

如果将elemIndexfindIndex的定义复制到模块中,问题就会消失:

代码语言:javascript
复制
import Control.Exception (evaluate)
import Control.DeepSeq (rnf)

import Data.Maybe (listToMaybe)
import Data.List (findIndices)

elemIndex       :: Eq a => a -> [a] -> Maybe Int
elemIndex x     = findIndex (x==)

findIndex       :: (a -> Bool) -> [a] -> Maybe Int
findIndex p     = listToMaybe . findIndices p

collatz :: Int -> Int
collatz n
  | even n    = n `quot` 2
  | otherwise = 3 * n + 1

steps' :: Int -> Int -> Maybe Int
steps' m = elemIndex 1 . take m . iterate collatz

main :: IO ()
main = evaluate $ rnf $ map (steps' 800) $ [1..10^7]

问题似乎是,这些必须是不可阻挡的,GHC才能得到正确的融合。不幸的是,它们在Data.OldList中都没有被标记为不可标记。

允许findIndex参与融合的更改是相对较新的(参见Trac 14387),其中listToMaybe被重新实现为foldr。所以,它可能还没有看到太多的测试。

票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51431355

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档