【发布时间】:2015-10-09 22:20:02
【问题描述】:
我需要从列表中取出最后一个n 元素,使用O(n) 内存所以我写了这段代码
take' :: Int -> [Int] -> [Int]
take' n xs = (helper $! (length $! xs) - n + 1) xs
where helper skip [] = []
helper skip (x : xs) = if skip == 0 then xs else (helper $! skip - 1) xs
main = print (take' 10 [1 .. 100000])
此代码占用O(|L|) 内存,其中|L| -- 是给定列表的长度。
但是当我写这段代码时
take' :: Int -> [Int] -> [Int]
take' n xs = helper (100000 - n + 1) xs
where helper skip [] = []
helper skip (x : xs) = if skip == 0 then xs else (helper $! skip - 1) xs
main = print (take' 10 [1 .. 100000])
此代码现在只占用O(n) 内存(唯一的变化是(helper $! (length $! xs) - n + 1) -> helper (100000 - n + 1))
所以,据我所知,Haskell 出于某种原因在第一次调用 helper 之前不会评估 length xs,因此它会在 skip 中留下一个 thunk,并且 Haskell 必须在每个堆栈帧中保留这个值,而不是进行尾递归。但在第二段代码中,它评估 (100000 - n + 1) 并将纯值赋予 helper。
所以问题是如何在第一次调用助手之前评估列表的长度并仅使用O(n)内存。
【问题讨论】:
-
有一个“众所周知的”技巧可以做到这一点,我不希望你在没有提示的情况下猜到。提示:
skip参数使用列表而不是数字。 -
@ØrjanJohansen 似乎解决方案是最后的答案。无论如何感谢您的提示 =)
标签: haskell