Haskell 有什么阻止优化尾部递归的吗?
我正在用动态编程解决Haskell的背包问题。我的第一次尝试是建立一个二维表格。但当输入较大时(例如,100*3190802表),内存很容易膨胀 知道任何给定的行Haskell 有什么阻止优化尾部递归的吗?,haskell,lazy-evaluation,tail-recursion,knapsack-problem,Haskell,Lazy Evaluation,Tail Recursion,Knapsack Problem,我正在用动态编程解决Haskell的背包问题。我的第一次尝试是建立一个二维表格。但当输入较大时(例如,100*3190802表),内存很容易膨胀 知道任何给定的行i只依赖于行(i-1),因此我编写了一个函数,希望利用尾部递归: import Data.Vector (Vector, (!)) import qualified Data.Vector as V -- n items, k capacity, vs values, ws weights ans:: Int -> Int -&
i
只依赖于行(i-1)
,因此我编写了一个函数,希望利用尾部递归:
import Data.Vector (Vector, (!))
import qualified Data.Vector as V
-- n items, k capacity, vs values, ws weights
ans:: Int -> Int -> Vector Int -> Vector Int -> Int
ans n k vs ws =
let row = initRow k vs ws
in row ! k
initRow :: Int -> Vector Int -> Vector Int -> Vector Int
initRow k vs ws = itbl 1 $ V.replicate (k + 1) 0
where n = V.length vs
itbl i row
| i > n = row
| otherwise = itbl (i + 1) $ V.generate (k + 1) gen
where gen w =
let w_i = ws ! (i - 1)
no_i = row ! w
ok_i = row ! (w - w_i) + (vs ! (i - 1))
in
if w < w_i then no_i
else max no_i ok_i
代码中是否有任何东西阻止编译器为尾部递归生成优化代码
--这是一个严格的问题。在中调用
generate
| otherwise = itbl (i + 1) $ V.generate (k + 1) gen
实际上不会将向量强制放入内存
您可以导入控制.DeepSeq并用严格的应用程序替换$
代码>:
| otherwise = itbl (i + 1) $!! V.generate (k + 1) gen
或者,您可以使用未绑定的向量(可能更快),方法是将import语句更改为
import Data.Vector.Unboxed (Vector, (!))
import qualified Data.Vector.Unboxed as V
(并将所有其他内容保留在原始程序中)。出于好奇,尝试从
itbl(i+1)$V.generate(k+1)gen
调用中删除itbl(i+1)(V.generate(k+1)gen)
。我猜,$
使调用不是尾部递归的。谢谢。但是删除$
似乎没有帮助。内存使用仍然在增长。我想这是懒惰的问题。在惰性语言中,尾部递归是不够的(也不总是可取的)。请尝试用$替换$
代码>。感谢大家指出正确的方向。是的,是关于严格。
import Data.Vector.Unboxed (Vector, (!))
import qualified Data.Vector.Unboxed as V