强制重新计算列表

时间:2012-06-06 17:45:40

标签: list haskell memory-management

下面的函数search搜索两个在某个函数下具有相同输出的输入。在搜索期间,它迭代输入列表xs两次,并且此输入列表可能非常大,例如, [0..1000000000]。我宁愿使用内存来存储由碰撞创建的HashSet,而不是存储xs的元素,我的理解是,即使xs可能被懒惰地计算,它也会被保留,以防万一拨打find时需要。

问题:

  • 这种理解是否正确?
  • 如果我将其保留为列表,那么如果将xs传递给find,我可以将xs重新计算出来吗?
  • 我可以使用替代数据结构xs,它允许我控制使用的空间吗? xs仅用于指定要检查的输入。

请注意import Data.HashSet as Set import Data.Hashable import Data.List search :: (Hashable b, Eq b) => (a->b) -> [a] -> Maybe (a,a) search h xs = do x0 <- collision h xs let h0 = h x0 x1 <- find (\x -> (h x) == h0) xs return (x0,x1) collision :: (Hashable b, Eq b) => (a->b) -> [a] -> Maybe a collision h xs = go Set.empty xs where go s [] = Nothing go s (x:xs) = if y `Set.member` s then Just x else go (Set.insert y s) xs where y = h x main = print $ search (\x -> x `mod` 21) ([10,20..2100] :: [Int]) 没有类型限制 - 它可以是任何类型的集合。

{{1}}

1 个答案:

答案 0 :(得分:6)

我在这里基本回答了这个问题:https://stackoverflow.com/a/6209279/371753

以下是相关代码。

import Data.Stream.Branching(Stream(..))
import qualified Data.Stream.Branching as S
import Control.Arrow
import Control.Applicative
import Data.List

data UM s a = UM (s -> Maybe a) deriving Functor
type UStream s a = Stream (UM s) a

runUM s (UM f) = f s
liftUM x = UM $ const (Just x)
nullUM = UM $ const Nothing

buildUStream :: Int -> Int -> Stream (UM ()) Int
buildUStream start end = S.unfold (\x -> (x, go x)) start
    where go x
           | x < end = liftUM (x + 1)
           | otherwise = nullUM

usToList x = unfoldr (\um -> (S.head &&& S.tail) <$> runUM () um) x

长话短说,不是传递列表,而是传递描述如何生成列表的数据类型。现在,您可以直接在流上编写函数,或者可以使用usToList函数来使用已有的列表函数。