gpt4 book ai didi

haskell - Haskell 中使用 Data.Map 进行动态编程?

转载 作者:行者123 更新时间:2023-12-02 05:57:50 28 4
gpt4 key购买 nike

我正在尝试在 Haskell 中实现一个简单的 dp 算法(这是针对欧拉项目的 Collat​​z 猜想问题);这是等效的 C++:

map<int,int> a;
int solve(int x) {
if (a.find(x) != a.end()) return a[x];
return a[x] = 1 + /* recursive call */;
}

所以我用 Haskell 编写的代码最终看起来像这样:

solve :: (Memo, Int) -> (Memo, Int)
solve (mem, x) =
case Map.lookup x mem of
Just l -> (mem, l)
Nothing -> let (mem', l') = {- recursive call -}
mem'' = Map.insert x (1+l') mem'
in (mem'', 1+l')

(我认为我只是在这里重新实现一个状态单子(monad),但暂时不用介意。)调用solve的代码尝试找到它可以为参数提供的最大值,最多K=1e6:

foldl'
(\(mem,ss) k ->
let (mem',x') = solve (mem, k)
in (mem', (x', k):ss))
(Map.singleton 1 1, [(1,1)]) [2..100000]

上面编写的代码因堆栈溢出而失败。我理解,这是可以预料到的,因为它构建了一个非常大的未评估的重击。所以我尝试使用

x' `seq` (mem', (x',k):ss)

在foldl'内部,它计算出K=1e5的正确答案。但对于 K=1e6 则失败(12 秒内堆栈溢出)。然后我尝试使用

mem'' `seq` l' `seq` (mem'', 1+l')

在解决的最后一行,但这没有什么区别(堆栈溢出仍然)。然后我尝试使用

mem'' `deepseq` l' `seq` (mem'', 1+l')

这非常慢,大概是因为 deepseq 遍历了整个映射内存,使得算法的时间复杂度是二次的,而不是 n*log(n)。

实现这个的正确方法是什么?我陷入困境,因为我无法弄清楚如何使整个计算严格,并且我不太确定计算的哪一部分导致堆栈溢出,但我怀疑它是映射。我可以使用例如数组,但我想了解我在这里做错了什么。

最佳答案

当您使用 32 位有符号整数类型时,堆栈溢出不会消失。对于某些起始值,链离开 32 位范围并进入负数的无限循环。使用IntegerInt64Word64

关于haskell - Haskell 中使用 Data.Map 进行动态编程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10083743/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com